Skip to main content

libfcp_server/
server.rs

1// Copyright Nixort <https://github.com/Nixort> 2026.
2//
3// License: GNU General Public License v3.0 only.
4// You can find the license file in the project root.
5//
6// Federated CFR Connect Protocol (FCP).
7
8//! Signed federation configuration publisher.
9
10use alloc::vec::Vec;
11
12use libfcp_core::{
13    EndpointIdentity, FederationConfiguration, FederationId, FederationMember,
14    SignedFederationConfiguration, SigningIdentity,
15};
16
17use crate::Error;
18
19/// Server-side authority that publishes one federation's signed settings.
20///
21/// The server owns policy publication only. Applications still decide how a
22/// client authenticates this authority key and how the signed bytes are carried
23/// to clients. The server is not a signaling relay and does not participate in
24/// a peer's WebRTC or CFR state machine.
25pub struct FederationServer {
26    signer: SigningIdentity,
27    configuration: FederationConfiguration,
28}
29
30impl FederationServer {
31    /// Creates an empty epoch-zero configuration with the supplied authority identity.
32    pub fn new(federation: FederationId, signer: SigningIdentity) -> Result<Self, Error> {
33        let authority = signer.endpoint();
34        let configuration = FederationConfiguration::new(federation, authority, 0, Vec::new())?;
35        Ok(Self {
36            signer,
37            configuration,
38        })
39    }
40
41    /// Returns the pinned authority identity clients must authenticate out of band.
42    pub fn authority(&self) -> EndpointIdentity {
43        self.configuration.authority
44    }
45
46    /// Returns the currently configured federation namespace.
47    pub fn federation(&self) -> FederationId {
48        self.configuration.federation
49    }
50
51    /// Returns the current monotonic policy version.
52    pub fn epoch(&self) -> u64 {
53        self.configuration.epoch
54    }
55
56    /// Replaces all explicit member bindings at a strictly newer epoch.
57    ///
58    /// An application must apply its admission and identity policy before calling
59    /// this method. In particular, an FCP endpoint identity and CFR identity key are
60    /// not considered equivalent simply because this server publishes them in one
61    /// record.
62    pub fn replace_members(
63        &mut self,
64        epoch: u64,
65        members: Vec<FederationMember>,
66    ) -> Result<(), Error> {
67        if epoch <= self.configuration.epoch {
68            return Err(Error::NonIncreasingEpoch);
69        }
70        self.configuration = FederationConfiguration::new(
71            self.configuration.federation,
72            self.configuration.authority,
73            epoch,
74            members,
75        )?;
76        Ok(())
77    }
78
79    /// Produces the canonical signed configuration artifact for application-selected delivery.
80    pub fn publish(&self) -> Result<SignedFederationConfiguration, Error> {
81        Ok(SignedFederationConfiguration::sign(
82            self.configuration.clone(),
83            &self.signer,
84        )?)
85    }
86}