Skip to main content

liminal_server/config/types/
open.rs

1//! `[open]`: how far an exchange with no `[auth]` reaches (ACCESS-011 R1).
2//!
3//! ACCESS-010 made an exchange with no `[auth]` open mode and bound it to
4//! loopback. This table is the operator's written choice to let that exchange
5//! listen on the network as well, for building fast on more than one machine;
6//! it changes nothing about what the exchange asks of anyone, which is still
7//! nothing. The table is refused beside `[auth]`, so it can never read as a
8//! way to loosen a gated exchange.
9
10/// The `[open]` table.
11#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Deserialize)]
12#[serde(deny_unknown_fields)]
13pub struct OpenConfig {
14    /// Where the open exchange may listen: loopback (the default without the
15    /// table) or the network.
16    #[serde(default)]
17    pub reach: Reach,
18    /// `[open.construction]`: the construction bounds of an open exchange
19    /// (ACCESS-015 R1), the same as `[auth.lys.construction.limits]` with no
20    /// grants. Present, every construction act runs as the declared holder's
21    /// own; absent, the site routes say construction is not configured.
22    #[serde(default)]
23    pub construction: Option<crate::services::lifecycle::site::SiteLimits>,
24}
25
26/// How far an open exchange or an open seat reaches.
27#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, serde::Deserialize)]
28#[serde(rename_all = "snake_case")]
29pub enum Reach {
30    /// This machine only: every listener on a loopback address.
31    #[default]
32    Loopback,
33    /// Any address the operator writes; every connection is still admitted.
34    Network,
35}
36
37impl Reach {
38    /// The word the configuration uses.
39    #[must_use]
40    pub const fn word(self) -> &'static str {
41        match self {
42            Self::Loopback => "loopback",
43            Self::Network => "network",
44        }
45    }
46}
47
48impl std::fmt::Display for Reach {
49    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50        formatter.write_str(self.word())
51    }
52}
53
54impl super::ServerConfig {
55    /// How far this exchange reaches: the `[open]` table's word, loopback
56    /// without one. Meaningful in open mode only; a gated exchange listens
57    /// where `[auth]` lets it and this answers loopback for it.
58    #[must_use]
59    pub fn open_reach(&self) -> Reach {
60        self.open.map_or(Reach::Loopback, |open| open.reach)
61    }
62
63    /// The construction bounds `[open.construction]` writes, if any.
64    #[must_use]
65    pub fn open_construction(&self) -> Option<crate::services::lifecycle::site::SiteLimits> {
66        self.open.and_then(|open| open.construction)
67    }
68}