diff options
| author | tv <tv@krebsco.de> | 2026-11-07 22:35:09 +0100 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-11-07 22:35:09 +0100 |
| commit | 1458ea92a41788a0f33e86e621817613f46055eb (patch) | |
| tree | 8cbe202657c5f9eb006b9612d9dfa0a4b829d589 /src/config | |
| parent | aea80cf1bfa39f17dbbd0b4782a71fca81e09f74 (diff) | |
dashboard: own links over the API, and CORS
GET /admin/dashboard/links/own and its event stream: a node's own links,
as LINKS_REPLY carried them, for other members' dashboards with a
token. CORS for the members' dashboard origins and --cors-origins,
without credentials.
Auth plan M3.
Diffstat (limited to 'src/config')
| -rw-r--r-- | src/config/mod.rs | 19 |
1 files changed, 19 insertions, 0 deletions
diff --git a/src/config/mod.rs b/src/config/mod.rs index 60ad413..f0e5dc5 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -138,6 +138,13 @@ pub(crate) const OPTIONS: &[OptionSpec] = &[ "How long after a login (POST /auth/login) its tokens may be refreshed; then the user logs in again.", ), option( + "cors-origins", + Kind::List, + "ORIGIN,[ORIGIN...]", + None, + "Origins (scheme://host[:port]) whose pages may read this node's own links and refresh tokens here, with a token (docs/access.md, Tokens): the dashboards of other members are allowed anyway, as the member list names them (dashboard-url). Without credentials: a page sends its token itself.", + ), + option( "bootstrap-users", Kind::List, "USER,[USER...]", @@ -557,6 +564,8 @@ pub(crate) struct Settings { pub(crate) protocol_writers: Vec<String>, #[serde(default)] pub(crate) bootstrap_users: Vec<String>, + #[serde(default)] + pub(crate) cors_origins: Vec<String>, #[serde( default = "default_token_lifetime", with = "crate::units::duration_option" @@ -790,6 +799,16 @@ impl Settings { if self.remake.is_some() && !self.genesis { bail!("remake makes a new swarm's document; it needs genesis"); } + if let Some(bad) = self.cors_origins.iter().find(|origin| { + url::Url::parse(origin) + .ok() + .filter(|url| url.origin().is_tuple()) + .is_none_or(|url| url.origin().ascii_serialization() != **origin) + }) { + bail!( + "cors-origins: {bad:?} isn't an origin (scheme://host[:port], no path; * isn't taken)" + ); + } if !self.bootstrap_users.is_empty() && !self.genesis { bail!( "bootstrap-users names the first users of a new swarm; it needs genesis (drop it once the swarm exists)" |
