Commit Graph
18 Commits
Author SHA1 Message Date
Security Fix 361b25a8bd hub: answer the local network only, whichever way a client arrives
The reported bug was the Hub being reachable from outside the local
network when Server + Desktop is active. c33457f guards the Caddy site
for sovransystemsos.local, but the Hub is an application that also
listens on a port of its own (8937), and a check in Caddy does nothing
for a client that never goes through Caddy. Whether a client could reach
the Hub depended on which door it used.

The Hub now asks the question itself. LanOnlyMiddleware is registered
outermost, so a client that is not on this computer or the local network
gets a bare 403 before authentication is considered; it never sees the
login page.

- Local means loopback, 10/8, 172.16/12, 192.168/16, 100.64/10
  (Tailscale and other CGNAT/VPN ranges) and 169.254/16 over IPv4, and
  ::1, fc00::/7 and fe80::/10 over IPv6.
- IPv6 global addresses are not on the list. A global address belonging
  to a laptop on the LAN cannot be told apart from a stranger's by the
  address alone, and 2000::/3 is every public IPv6 address there is.
- ::ffff:a.b.c.d is read as the IPv4 address inside it.
- sovran_systemsOS.hub.extraLanNetworks adds networks (IPv4 or IPv6 CIDR)
  for setups whose own devices use addresses outside those ranges. It is
  checked at build time. The app ignores an entry it cannot parse and
  refuses 0.0.0.0/0 and ::/0: it must never widen its policy by
  guessing, and "everyone" is hub.lanOnly = false, asked for by name.
- sovran_systemsOS.hub.lanOnly (default true) turns the check off.
- The first refusal from each address is logged, naming the option to
  change, so an operator whose own device is refused can find out why.
  The list is capped so a scanner cannot fill the journal or memory.

Behind Caddy the policy applies to the real client, not to Caddy: uvicorn
takes the address from X-Forwarded-For only when the peer is 127.0.0.1.

Checked, not only reviewed:
- The real app with the config.json the module really generates (nix
  eval on the nixpkgs revision flake.lock pins, read back from the
  derivation), on a real socket with the source address chosen per
  request: 127.0.0.1, 192.168/16, 100.64/10 and a declared extra
  network are served; 203.0.113.9, 8.8.4.4 and an address just outside
  the declared /28 get 403 on /login, / and /api/ping. /auto-login still
  answers 303 to loopback and 403 to everyone else.
- With c33457f's Caddy guard in front, an IPv6 client at 2001:db8::9
  passes Caddy (it is inside 2000::/3) and is refused by the Hub; an
  IPv4 stranger has the connection closed by Caddy; a LAN client is
  served.
- hub.extraLanNetworks accepts 203.0.113.0/28, 2001:db8:abcd::/48 and
  bare hosts, and fails the build for /33, 300.1.1.1/8, 0.0.0.0/0, ::/0,
  2001:db8::/129 and junk, with a message that says what to write.

Add tests/test_lan_policy.py and tests/test_hub_lan_only.py, and a note
in SECURITY.md.
2026-10-02 02:24:29 -05:00
Arena.ai Agent 2d777450e1 ddns: take the public IP from Njal.la only and give it to LiveKit
The Hub no longer asks a STUN server, a public DNS resolver or a "what
is my IP" service for the home IP address. The DDNS update asks Njal.la
to use the address the request comes from ("&auto"), reads back the
address Njal.la says it recorded and saves it to
/var/lib/secrets/external-ip. Njal.la is the only third party that
learns the address; it has to, to publish it.

- Add app/sovran_systemsos_web/ddns_update.py, installed as
  /etc/sovran/ddns-update.py and run by sovran-ddns-update.service. It
  runs curl --ipv4 without redirects, accepts only a public IPv4
  address, and rewrites the file atomically and only when the address
  changes. Stored "&a=${IP}" URLs are converted when they are used and
  "&quiet" is dropped.
- Rewrite modules/core/njalla.nix around that runner and delete
  modules/core/public-ip.nix. Setting a sovran_systemsOS.publicIP.*
  option now fails with a message that says where the address comes
  from. Activation removes the old scripts in /var/lib/sovran. The
  existing external-ip file keeps working.
- server.py reads the saved address and starts
  sovran-ddns-update.service after a domain is saved, instead of looking
  the address up itself.
- Element calling uses sovran_systemsOS.elementCalling.externalIP if
  set, otherwise the saved address, and fails with a clear message when
  neither exists or the address is not public. It no longer falls back
  to STUN. livekit-external-ip.path re-runs livekit-turn-setup and
  starts LiveKit when the address changes.
- Add tests/test_ddns_update.py.
2026-10-01 21:43:47 -05:00
naturallaw777 c54dbfe2a5 feat(element-calling): fix Element X discovery and harden federated calling
The element-calling feature only advertised the LiveKit focus via the
well-known org.matrix.msc4143.rtc_foci file, and relied on STUN
auto-detection for the public IP. Element X queries the MatrixRTC
transports registry endpoint and fails with MISSING_MATRIX_RTC_TRANSPORT
when it is absent, and blocked STUN egress silently left LiveKit
advertising a private IP (call connects but no video across servers).

- synapse: enable msc4143_enabled and advertise matrix_rtc.transports
  (MSC4519) with the site's element-calling URL, so Element X can
  discover the LiveKit focus instead of erroring out
- livekit: determine the public IP to advertise at runtime —
  explicit pin, then HTTPS egress detection (api.ipify.org /
  checkip.amazonaws.com / ifconfig.me), then STUN fallback with a
  warning; reject non-routable results (private/loopback/CGNAT)
- lk-jwt-service: append optional extra homeservers to
  LIVEKIT_FULL_ACCESS_HOMESERVERS via the new
  sovran_systemsOS.elementCalling.fullAccessHomeservers option
- add sovran_systemsOS.elementCalling.externalIP option to pin the
  advertised public IP for multi-WAN/VPN setups
- add element-calling-public-check.service: boot-time diagnostics for
  public DNS (via 1.1.1.1, bypassing local loopback overrides), JWT
  healthz through Caddy and via the public IP, and the transports
  endpoint — turns the silent -no media- failure into a visible error
- add restartTriggers so livekit/lk-jwt-service pick up regenerated
  runtime configs on rebuild
2026-08-20 14:07:06 -05:00
naturallaw777 30b753ec40 feat: add Bitcoin Core Tor IBD gossip control 2026-08-15 14:44:13 -05:00
naturallaw777 3541f6baa1 Replace Bitcoin Knots with Bitcoin Core 2026-08-13 13:43:17 -05:00
naturallaw777andarena-agent aa4ffaa803 Rename NWC feature to Lightning Wallet Connections and split modal into tabs
Naming: user-facing 'Wallet Connections' -> 'Lightning Wallet Connections'
across the Hub, feature registry, tile, and NixOS modules. Internal ids
(nwc-wallets, albyhub.service, /api/nwc/*) are unchanged.

UX: the service-detail modal put status, domain diagnostics, router ports,
the enable/disable toggle, restart, the liquidity guide and the whole wallet
manager in one cramped scrolling column. For this feature the modal is now
980px wide and split into two tabs:

  - Wallets: wallet grid, create/share/verify flows, collapsible liquidity guide
  - Service & Setup: description, status, domain checklist, ports, enable, restart

A status dot and domain chip sit in the tab bar so state is visible from both
tabs, and the modal opens on Setup when the service is off or the Lightning
Address domain is unconfigured. Wallet cards gain a balance chip, pending
badge, a prominent address row, and separated destructive actions.

Non-NWC services keep the original single-column layout and width.

Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
2026-07-29 01:59:28 +00:00
copilot-swe-agent[bot] 9673f6733a feat: add hub-managed Wallet Connections scaffolding 2026-07-27 02:10:11 +00:00
copilot-swe-agent[bot] e1ae63e8bc Add deprecated bip110 no-op shim and Hub migration
- modules/core/roles.nix: re-declare bip110 as a nullOr bool no-op
  option so existing custom.nix files with `lib.mkForce true` continue
  to evaluate; add config.warnings block that fires only when the stale
  flag is explicitly set
- server.py: add DEPRECATED_FEATURE_IDS constant; skip deprecated ids
  in _read_hub_overrides and _write_hub_overrides; add
  _migrate_strip_deprecated_features helper that rewrites the Hub
  Managed section without deprecated lines on startup; add
  @app.on_event("startup") handler _startup_migrate_deprecated_features
2026-06-04 19:16:36 +00:00
copilot-swe-agent[bot] 753e136384 Retire deprecated bip110 flake input; collapse Bitcoin node tiles to two 2026-06-04 18:52:28 +00:00
copilot-swe-agent[bot]andnaturallaw777 b6ac6174fe Fix: BTCPay off by default in Node role, Caddy conditional ACME/ports
Agent-Logs-Url: https://github.com/naturallaw777/staging_alpha/sessions/2e2b84a8-c5e9-4eea-8bee-fc587bb3a6fa

Co-authored-by: naturallaw777 <99053422+naturallaw777@users.noreply.github.com>
2026-04-13 22:55:37 +00:00
copilot-swe-agent[bot]andnaturallaw777 97f37b8dfe feat: add sovran_systemsOS.caddy.extraVirtualHosts NixOS option
Agent-Logs-Url: https://github.com/naturallaw777/staging_alpha/sessions/e966dd20-b74e-4ec5-b4db-68aa06129162

Co-authored-by: naturallaw777 <99053422+naturallaw777@users.noreply.github.com>
2026-04-07 13:06:35 +00:00
copilot-swe-agent[bot]andnaturallaw777 ef1e2706f2 feat: move sshd into its own Nix feature module, gate Tech Support behind it
Agent-Logs-Url: https://github.com/naturallaw777/staging_alpha/sessions/d45dc36f-0b3b-48bb-950f-700afe45dd06

Co-authored-by: naturallaw777 <99053422+naturallaw777@users.noreply.github.com>
2026-04-05 15:09:02 +00:00
naturallaw777 5accb18e7c updated branding and some retooling 2026-03-29 07:13:22 -05:00
naturallaw777 7509807938 added tooling for domains 2026-03-27 17:12:11 -05:00
naturallaw777 8161796fdb fixed roles 2026-03-27 15:42:21 -05:00
naturallaw777 5e9a01e061 fixed bip110 declar 2026-03-27 15:16:50 -05:00
naturallaw777 bec00bd506 set services to default retooling 2026-03-27 14:58:45 -05:00
naturallaw777 e1e9376792 initial retooling 2026-03-27 14:23:08 -05:00