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}