feat(host): §8a — require native pairing by default (serve --open to disable)
ci / rust (push) Has been cancelled
ci / rust (push) Has been cancelled
An open punktfunk/1 host any LAN device can trust-on-first-use and stream from is
insecure. The unified host now gates native sessions on pairing by DEFAULT: a client
must complete the SPAKE2 PIN ceremony (armed from the web console) before it's
admitted; paired devices persist. `serve --open` keeps the old TOFU behavior for
trusted single-user setups.
native_serve_opts now takes a NativeServe { port, require_pairing }; parse_serve
builds it with require_pairing = !--open. GameStream pairing (separate) is unchanged.
The require_pairing gate + ceremony are already covered by m3::pairing_ceremony_and_gate.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -145,17 +145,17 @@ impl AppState {
|
||||
}
|
||||
|
||||
/// Run the host (blocks): mDNS, the nvhttp servers, and the management REST API.
|
||||
/// `native_port = Some(p)` makes this the **unified** host — it also runs the native punktfunk/1
|
||||
/// QUIC server on `p` in the same process, sharing one [`crate::native_pairing`] handle with the
|
||||
/// management API so the web console can arm pairing and show the PIN. `None` = GameStream only
|
||||
/// `native = Some(cfg)` makes this the **unified** host — it also runs the native punktfunk/1
|
||||
/// QUIC server on `cfg.port` in the same process, sharing one [`crate::native_pairing`] handle with
|
||||
/// the management API so the web console can arm pairing and show the PIN. `None` = GameStream only
|
||||
/// (the mgmt API's native endpoints report `enabled: false`).
|
||||
pub fn serve(mgmt: crate::mgmt::Options, native_port: Option<u16>) -> Result<()> {
|
||||
pub fn serve(mgmt: crate::mgmt::Options, native: Option<crate::m3::NativeServe>) -> Result<()> {
|
||||
let host = Host::detect()?;
|
||||
let identity = cert::ServerIdentity::load_or_create().context("host certificate")?;
|
||||
let state = Arc::new(AppState::new(host, identity));
|
||||
// The shared native-pairing handle exists only when we run the native host; it links the QUIC
|
||||
// ceremony and the management API.
|
||||
let native = match native_port {
|
||||
let np = match &native {
|
||||
Some(_) => Some(Arc::new(
|
||||
crate::native_pairing::NativePairing::load_with(None, None, false)
|
||||
.context("native pairing store")?,
|
||||
@@ -166,7 +166,8 @@ pub fn serve(mgmt: crate::mgmt::Options, native_port: Option<u16>) -> Result<()>
|
||||
hostname = %state.host.hostname,
|
||||
uniqueid = %state.host.uniqueid,
|
||||
ip = %state.host.local_ip,
|
||||
native = native_port.is_some(),
|
||||
native = native.is_some(),
|
||||
require_pairing = native.as_ref().map(|n| n.require_pairing),
|
||||
"punktfunk host (GameStream P1.1: serverinfo + pairing + mDNS)"
|
||||
);
|
||||
let rt = tokio::runtime::Runtime::new().context("build tokio runtime")?;
|
||||
@@ -176,13 +177,17 @@ pub fn serve(mgmt: crate::mgmt::Options, native_port: Option<u16>) -> Result<()>
|
||||
let _advert = mdns::advertise(&state.host).context("mDNS advertise")?;
|
||||
rtsp::spawn(state.clone()).context("start RTSP server")?;
|
||||
control::spawn(state.clone()).context("start ENet control server")?;
|
||||
match (native_port, native) {
|
||||
(Some(port), Some(np)) => {
|
||||
tracing::info!(port, "unified host: also serving native punktfunk/1 (QUIC)");
|
||||
match (native, np) {
|
||||
(Some(cfg), Some(np)) => {
|
||||
tracing::info!(
|
||||
port = cfg.port,
|
||||
require_pairing = cfg.require_pairing,
|
||||
"unified host: also serving native punktfunk/1 (QUIC)"
|
||||
);
|
||||
tokio::try_join!(
|
||||
nvhttp::run(state.clone()),
|
||||
crate::mgmt::run(state.clone(), mgmt, Some(np.clone())),
|
||||
crate::m3::serve(crate::m3::native_serve_opts(port), np),
|
||||
crate::m3::serve(crate::m3::native_serve_opts(&cfg), np),
|
||||
)?;
|
||||
}
|
||||
_ => {
|
||||
|
||||
Reference in New Issue
Block a user