The networking section is read from constants and written to nothing #169

Closed
opened 2026-08-21 11:51:52 +02:00 by Claude · 1 comment
Collaborator

The networking page saves nothing but the remote-access checkbox, and answers
204 for the rest — so the dashboard reports a save that did not happen and
every field is back to what it was on the next load.

Posted through POST /System/Configuration/network and read straight back:

post 204
AutoDiscovery                posted=False                          readback=True
BaseUrl                      posted='/jf'                          readback=''
PublicHttpPort               posted=9096                           readback=8096
PublishedServerUriBySubnet   posted=['all=https://media.example']   readback=[]
KnownProxies                 posted=['10.0.0.5']                   readback=[]
EnableRemoteAccess           posted=True                           readback=True

crates/ephyra-http/src/routes/admin/configuration.rs::update_section parses
the body into a NetworkConfiguration, assigns
config.server.enable_remote_access, and drops the object.

The read side is not the configuration either. network() in the same file
builds the section from literals — internal_https_port: 8920,
auto_discovery: true, enable_i_pv4: true — and leaves the rest at
NetworkConfiguration::default(). It reads neither config.server.published_url
nor config.discovery.enabled, so a server configured with either reports the
opposite of what it is running.

Three of those fields are settings this server has. server.bind,
server.published_url (crates/ephyra-core/src/config/server.rs:26, which is
what a stream URL is built from behind a proxy) and discovery.enabled
(crates/ephyra-server/src/discovery.rs:50, which decides whether the broadcast
probe is answered). All three are reachable by editing config.toml and
restarting, and by nothing a client can do. Upstream persists the whole
NetworkConfiguration and serves it back.

Where to start

The three above are the ones with somewhere to go: AutoDiscovery onto
discovery.enabled, the published-URL fields onto server.published_url, and
the port onto server.bind — the last needs upstream's restart-to-apply, since
the listener is already bound.

The rest of the section — HTTPS and its certificate, UPnP, the LAN subnet lists,
the remote-IP filter, the known proxies — is configuration this server does not
have, and docs/install.md says as much about the proxy fields deliberately.
Storing them so they read back is one answer; refusing them is another. Taking
them and reporting success is the one that misleads.

How to know it is done

Turning off autodiscovery on the networking page survives a reload and stops the
broadcast answer; setting a published URL there is what a stream URL is built
from afterwards. A test that posts a section and reads it back, failing today.

House rules

CLAUDE.md is the short version and these are the parts that bite: tests run
under cargo nextest; upstream's source is the checkout in upstream/ at the
pin
; generated files are regenerated rather than edited; a comment says what
the code does, not how it got there.

A test that cannot fail is worse than none.

The networking page saves nothing but the remote-access checkbox, and answers `204` for the rest — so the dashboard reports a save that did not happen and every field is back to what it was on the next load. Posted through `POST /System/Configuration/network` and read straight back: post 204 AutoDiscovery posted=False readback=True BaseUrl posted='/jf' readback='' PublicHttpPort posted=9096 readback=8096 PublishedServerUriBySubnet posted=['all=https://media.example'] readback=[] KnownProxies posted=['10.0.0.5'] readback=[] EnableRemoteAccess posted=True readback=True `crates/ephyra-http/src/routes/admin/configuration.rs::update_section` parses the body into a `NetworkConfiguration`, assigns `config.server.enable_remote_access`, and drops the object. **The read side is not the configuration either.** `network()` in the same file builds the section from literals — `internal_https_port: 8920`, `auto_discovery: true`, `enable_i_pv4: true` — and leaves the rest at `NetworkConfiguration::default()`. It reads neither `config.server.published_url` nor `config.discovery.enabled`, so a server configured with either reports the opposite of what it is running. **Three of those fields are settings this server has.** `server.bind`, `server.published_url` (`crates/ephyra-core/src/config/server.rs:26`, which is what a stream URL is built from behind a proxy) and `discovery.enabled` (`crates/ephyra-server/src/discovery.rs:50`, which decides whether the broadcast probe is answered). All three are reachable by editing `config.toml` and restarting, and by nothing a client can do. Upstream persists the whole `NetworkConfiguration` and serves it back. ## Where to start The three above are the ones with somewhere to go: `AutoDiscovery` onto `discovery.enabled`, the published-URL fields onto `server.published_url`, and the port onto `server.bind` — the last needs upstream's restart-to-apply, since the listener is already bound. The rest of the section — HTTPS and its certificate, UPnP, the LAN subnet lists, the remote-IP filter, the known proxies — is configuration this server does not have, and `docs/install.md` says as much about the proxy fields deliberately. Storing them so they read back is one answer; refusing them is another. Taking them and reporting success is the one that misleads. ## How to know it is done Turning off autodiscovery on the networking page survives a reload and stops the broadcast answer; setting a published URL there is what a stream URL is built from afterwards. A test that posts a section and reads it back, failing today. ### House rules `CLAUDE.md` is the short version and these are the parts that bite: tests run under `cargo nextest`; upstream's source is the checkout in `upstream/` **at the pin**; generated files are regenerated rather than edited; a comment says what the code does, not how it got there. A test that cannot fail is worse than none.
Author
Collaborator

Landed in 61eb033, with review fixes in 9f43537.

Three fields have somewhere real to go and now round-trip:

  • AutoDiscovery onto discovery.enabled, which decides whether the broadcast
    probe is answered.
  • PublishedServerUriBySubnet onto server.published_url, which is what a
    stream URL is built from behind a proxy. The unscoped all= entry only:
    upstream applies a scoped one to the clients whose address it matches, and
    this server has one URL for everybody — promoting a LAN-only override to it
    would hand a remote client an address it cannot reach.
  • The port onto server.bind, taking effect on the next start because the
    listener is already bound.

The review caught the port being the wrong one. It was PublicHttpPort;
upstream binds InternalHttpPort (ApplicationHost.cs: HttpPort = networkConfiguration.InternalHttpPort) and the public one is what it
advertises. Behind a proxy those are different numbers — 8096 and 443 — so
binding the advertised one would have abandoned the port the proxy points at,
and tried to bind a privileged one. The IPv4 and IPv6 flags are read off what
the listener is actually on, and the HTTPS ports report upstream's default 8920
rather than the DTO's zero.

The rest — HTTPS and its certificate, UPnP, the LAN subnet lists, the remote-IP
filter, the known proxies — is configuration this server does not have, and
docs/install.md says as much about the proxy fields. It is taken and not
stored, and reported absent rather than as a value the page would show and
nothing would honour. Storing it would make the page disagree with itself.

Landed in 61eb033, with review fixes in 9f43537. Three fields have somewhere real to go and now round-trip: - `AutoDiscovery` onto `discovery.enabled`, which decides whether the broadcast probe is answered. - `PublishedServerUriBySubnet` onto `server.published_url`, which is what a stream URL is built from behind a proxy. The unscoped `all=` entry only: upstream applies a scoped one to the clients whose address it matches, and this server has one URL for everybody — promoting a LAN-only override to it would hand a remote client an address it cannot reach. - The port onto `server.bind`, taking effect on the next start because the listener is already bound. The review caught the port being the wrong one. It was `PublicHttpPort`; upstream binds `InternalHttpPort` (`ApplicationHost.cs`: `HttpPort = networkConfiguration.InternalHttpPort`) and the public one is what it advertises. Behind a proxy those are different numbers — 8096 and 443 — so binding the advertised one would have abandoned the port the proxy points at, and tried to bind a privileged one. The IPv4 and IPv6 flags are read off what the listener is actually on, and the HTTPS ports report upstream's default 8920 rather than the DTO's zero. The rest — HTTPS and its certificate, UPnP, the LAN subnet lists, the remote-IP filter, the known proxies — is configuration this server does not have, and `docs/install.md` says as much about the proxy fields. It is taken and not stored, and reported absent rather than as a value the page would show and nothing would honour. Storing it would make the page disagree with itself.
Sign in to join this conversation.
No description provided.