Merge pull request 'fix(companion): guarantee dual-path peering — LAN p2p + public anchor, always' (#109) from fix/guaranteed-anchor-peering into main
All checks were successful
Demo images / Build & push demo images (push) Successful in 2m56s

This commit is contained in:
lfg2025 2026-07-23 21:18:00 +00:00
commit db2cafc657
5 changed files with 48 additions and 12 deletions

View File

@ -11,8 +11,8 @@ android {
applicationId = "com.archipelago.app" applicationId = "com.archipelago.app"
minSdk = 26 minSdk = 26
targetSdk = 35 targetSdk = 35
versionCode = 22 versionCode = 23
versionName = "0.5.2" versionName = "0.5.3"
vectorDrawables { vectorDrawables {
useSupportLibrary = true useSupportLibrary = true

View File

@ -12,6 +12,16 @@ import androidx.datastore.preferences.preferencesDataStore
private val Context.fipsDataStore: DataStore<Preferences> by preferencesDataStore(name = "fips_prefs") private val Context.fipsDataStore: DataStore<Preferences> by preferencesDataStore(name = "fips_prefs")
// Archipelago-operated public anchor (vps2). Baked in so EVERY pairing yields
// both paths — direct LAN p2p to the node AND a public rendezvous for
// away-from-home — even when the scanned node is old enough that its QR
// carries no fanchors. Keep in lockstep with
// core/archipelago/src/fips/anchors.rs (ARCHY_ANCHOR_*).
internal const val ARCHY_ANCHOR_NPUB =
"npub1dptaktwxv0mm245g2lqjykwm5ll0jpc6m3r4242ydfa9z7qe6urs3jvrak"
internal const val ARCHY_ANCHOR_ADDR = "146.59.87.168:8444"
internal const val ARCHY_ANCHOR_TRANSPORT = "tcp"
/** /**
* Mesh identity + known node peers. Follows the same plaintext-DataStore * Mesh identity + known node peers. Follows the same plaintext-DataStore
* storage model as ServerPreferences (the server password lives there the * storage model as ServerPreferences (the server password lives there the
@ -91,6 +101,21 @@ class FipsPreferences(private val context: Context) {
})) }))
} }
} }
// Guarantee the public anchor: without it, a QR from an older node
// leaves the phone LAN-only and pairing/connecting dies off-LAN.
if (info.npub != ARCHY_ANCHOR_NPUB &&
incoming.none { it.optString("npub") == ARCHY_ANCHOR_NPUB }
) {
incoming += JSONObject().apply {
put("npub", ARCHY_ANCHOR_NPUB)
put("alias", "Archipelago anchor")
put("addresses", JSONArray().put(JSONObject().apply {
put("transport", ARCHY_ANCHOR_TRANSPORT)
put("addr", ARCHY_ANCHOR_ADDR)
put("priority", 40)
}))
}
}
val incomingNpubs = incoming.map { it.optString("npub") }.toSet() val incomingNpubs = incoming.map { it.optString("npub") }.toSet()
context.fipsDataStore.edit { prefs -> context.fipsDataStore.edit { prefs ->
val current = JSONArray(prefs[peersKey] ?: "[]") val current = JSONArray(prefs[peersKey] ?: "[]")

View File

@ -185,8 +185,10 @@ fun ServerConnectScreen(
useHttps = false, useHttps = false,
port = "", port = "",
) )
// The tunnel + mesh route need a moment on cold start. // The tunnel + mesh route need a moment on cold start — and on
for (attempt in 0 until 4) { // a first-ever pairing the VPN consent dialog is on screen at
// the same time, so give the user time to tap it.
for (attempt in 0 until 6) {
if (attempt > 0) delay(2000) if (attempt > 0) delay(2000)
reachable = testConnection(meshServer) reachable = testConnection(meshServer)
if (reachable) break if (reachable) break

View File

@ -18,8 +18,11 @@ user's hands.
support; web scan modal hands live scanning to it. support; web scan modal hands live scanning to it.
- npub-keyed saved servers (pairing contract item 1, PR #106). - npub-keyed saved servers (pairing contract item 1, PR #106).
- Served APK refreshed: `neode-ui/public/packages/archipelago-companion.apk` - Served APK refreshed: `neode-ui/public/packages/archipelago-companion.apk`
is now **0.5.2 / versionCode 22**, which additionally fixes the two field is now **0.5.3 / versionCode 23**. On top of the 0.5.1 scanner fixes it
failures from the user's 5G test (screenshots, 21:54): guarantees dual-path peering — the node's LAN endpoint (direct p2p, npub-
keyed dial hints) AND the Archipelago public anchor (vps2, baked into the
app so even an old node's QR can't leave the phone LAN-only) — and fixes
the two field failures from the user's 5G test (screenshots, 21:54):
- **Mesh VPN no longer kills the phone's internet** — the IPv6-only TUN - **Mesh VPN no longer kills the phone's internet** — the IPv6-only TUN
never called `allowFamily(AF_INET)`, so Android blocked all IPv4 while never called `allowFamily(AF_INET)`, so Android blocked all IPv4 while
the mesh was up. Now allowed (+ `allowBypass`). the mesh was up. Now allowed (+ `allowBypass`).
@ -39,9 +42,15 @@ user's hands.
3. The demo stack gets its images from CI (run 100 pushed today with the new 3. The demo stack gets its images from CI (run 100 pushed today with the new
web bundle) — confirm the Portainer stack re-pulled, or trigger its web bundle) — confirm the Portainer stack re-pulled, or trigger its
redeploy, so the demo QR also serves vc21. redeploy, so the demo QR also serves vc21.
4. Re-test the user's exact flow: node UI → Companion popup → download APK 4. **Node side is half the 5G story**: away-from-home reachability needs the
via QR → install (vc21 updates vc19/vc20 in place) → scan the pairing QR. NODE connected to the public anchor too. On Framework PT (and any test
If the scan still fails on-device with vc21, capture `adb logcat` around node): deploy current main (node-side npub-first `fips.pair-info`), then
the scan and report back — the parser accepts the npub-first QR verify `sudo -n fipsctl show status` reports the anchor connected —
(`fanchors` self-anchor first), so a remaining failure would be camera- `fips.reconnect` RPC if not. A phone can dial the anchor perfectly and
hardware-specific, not format. still fail if the node never enrolled with it.
5. Re-test the user's exact flows with vc23 (updates any older install in
place): (a) pair ON the LAN, then switch the phone to 5G — the UI must
come up via the mesh ULA; (b) pair while ALREADY on 5G (never on the
node's LAN) — scan, VPN consent, and the connect must succeed through
the anchor. If either fails, capture `adb logcat` around the attempt and
`fipsctl show sessions` on the node, and report back.