Skip to main content

ChannelConfig

Struct ChannelConfig 

Source
pub struct ChannelConfig {
    pub channel_id: ChannelId,
    pub visibility: Visibility,
    pub publish_caps: Option<CapabilityFilter>,
    pub subscribe_caps: Option<CapabilityFilter>,
    pub require_token: bool,
    pub token_roots: Vec<EntityId>,
    pub subscriber_origin_binding: Option<OriginBinding>,
    pub queue_group_policy: QueueGroupPolicy,
    pub priority: u8,
    pub reliable: bool,
    pub max_rate_pps: Option<u32>,
}
Expand description

Channel configuration with capability-based access control.

Authorization flow:

  1. Node announces capabilities via CapabilityAd
  2. If publish_caps is set, node’s CapabilitySet must match the filter
  3. If require_token is true, node must also have a valid PermissionToken
  4. On success, (origin_hash, channel_hash) is inserted into the AuthGuard

§Capability filters are advisory, not an access boundary

publish_caps / subscribe_caps match against a node’s self-advertised CapabilitySet: a peer declares its own capabilities in its own signed announcement, so any peer can satisfy a cap-filter simply by advertising the required tag (e.g. self-asserting role:admin). Treat cap-filters as matchmaking / intent-routing, not as a security boundary.

The actual access boundary is require_token + token_roots: a root-anchored TokenChain cannot be forged because each link is signature-verified up to a root the channel explicitly trusts. Any channel that must restrict who can publish or subscribe must use token enforcement; a cap-filter alone restricts nothing.

Fields§

§channel_id: ChannelId

Channel identity (name + hash).

§visibility: Visibility

Visibility scope for subnet routing.

§publish_caps: Option<CapabilityFilter>

Capability requirements for publishing. None = any node can publish. Advisory only — matched against the node’s self-advertised caps; use require_token for a real boundary.

§subscribe_caps: Option<CapabilityFilter>

Capability requirements for subscribing. None = any node can subscribe. Advisory only — matched against the node’s self-advertised caps; use require_token for a real boundary.

§require_token: bool

Whether a valid PermissionToken is required (in addition to capabilities).

§token_roots: Vec<EntityId>

Entities whose signature roots a valid token chain for this channel — the channel’s root(s) of trust.

When require_token is set, a presented TokenChain is only honored if its root link (tokens[0].issuer) is one of these entities. This is the anchor the bare-token path lacked: without it check/can_subscribe only verified a token was internally self-consistent (the named issuer signed it), so any peer could self-issue issuer = subject = self and pass. An empty token_roots combined with require_token = true fails closed — there is no authority a chain could anchor to, so nothing is authorized.

§subscriber_origin_binding: Option<OriginBinding>

Bind the dynamic name suffix to the subscriber’s own pinned identity. None (default) = any peer that clears the other gates may subscribe to any name this config covers.

Only meaningful on a prefix-registered config; see OriginBinding. Unlike publish_caps / subscribe_caps, this is an access boundary — it is evaluated against the TOFU-pinned peer identity, which a peer cannot self-assert.

§queue_group_policy: QueueGroupPolicy

Who may join a queue group on this channel. See QueueGroupPolicy; defaults to Unrestricted, which is the historical behaviour.

§priority: u8

Default priority level for this channel’s packets (0 = lowest).

§reliable: bool

Default reliability mode for streams on this channel.

§max_rate_pps: Option<u32>

Optional rate limit in packets per second.

Implementations§

Source§

impl ChannelConfig

Source

pub fn new(channel_id: ChannelId) -> Self

Create a new channel config with defaults (open access, global visibility).

Source

pub fn with_visibility(self, visibility: Visibility) -> Self

Set visibility.

Source

pub fn with_publish_caps(self, filter: CapabilityFilter) -> Self

Set capability requirements for publishing.

Advisory matchmaking, not access control: caps are self-advertised, so any peer can satisfy the filter by declaring the tag. Combine with Self::with_token_roots to actually restrict publishers.

Source

pub fn with_subscribe_caps(self, filter: CapabilityFilter) -> Self

Set capability requirements for subscribing.

Advisory matchmaking, not access control: caps are self-advertised, so any peer can satisfy the filter by declaring the tag. Combine with Self::with_token_roots to actually restrict subscribers.

Source

pub fn with_require_token(self, require: bool) -> Self

Require a valid permission token.

Source

pub fn with_token_roots(self, roots: Vec<EntityId>) -> Self

Require a token chain rooted at one of roots. Sets require_token = true and installs the channel’s authorizing root(s). This is the safe way to turn on token enforcement — with_require_token(true) alone (no roots) fails every authorization closed, since a chain has no authority to anchor to.

Source

pub fn token_required(&self) -> bool

Whether this channel enforces token authorization.

Enforcement is on when require_token is set or any token_roots are configured. Coupling the two means a config that names roots but forgot to flip require_token (e.g. built by struct literal or direct field assignment rather than Self::with_token_roots) still enforces, instead of silently admitting every peer — the fields are both public, so the invariant can’t be guaranteed at construction. All token gates (subscribe, publish, the periodic sweep, the publish re-check) consult this rather than require_token directly.

Source

pub fn with_subscriber_origin_binding(self, binding: OriginBinding) -> Self

Bind this (prefix-registered) channel family’s dynamic suffix to the subscribing peer’s own pinned identity — see OriginBinding.

Callers subscribing to a bound family must have had their identity pinned on the publisher first, which happens when their signature-verified direct capability announcement arrives. A peer that has not announced is rejected (fail closed).

Source

pub fn caps_allow_subscribe(&self, node_caps: &CapabilitySet) -> bool

Do this node’s advertised capabilities satisfy the channel’s subscribe_caps filter?

Split out of Self::can_subscribe for the TokenBound queue-group path, which supplies its own token authority (the group grant) but must still apply the capability filter. Advisory, like every cap filter — see the type docs.

Source

pub fn with_queue_group_policy(self, policy: QueueGroupPolicy) -> Self

Restrict who may join a queue group on this channel — see QueueGroupPolicy.

Source

pub fn can_join_queue_group( &self, entity_id: &EntityId, channel: &str, group: &str, chain: Option<&TokenChain>, revocation: &RevocationRegistry, skew_secs: u64, ) -> bool

Does chain authorize this peer to join queue group group on channel?

Returns true when the channel places no restriction. Under QueueGroupPolicy::TokenBound the chain must root at one of this channel’s token_roots, bind at its leaf to entity_id, and authorize SUBSCRIBE on the derived group-grant hash — a grant naming the specific group, not the channel.

Fails closed: Deny refuses, and TokenBound with no chain (or no roots) refuses.

Source

pub fn with_priority(self, priority: u8) -> Self

Set default priority.

Source

pub fn with_reliable(self, reliable: bool) -> Self

Set default reliability.

Source

pub fn with_rate_limit(self, pps: u32) -> Self

Set rate limit.

Source

pub fn can_publish( &self, node_caps: &CapabilitySet, entity_id: &EntityId, channel_hash: ChannelHash, chain: Option<&TokenChain>, revocation: &RevocationRegistry, skew_secs: u64, ) -> bool

Check if entity_id is authorized to publish on channel_hash, presenting chain.

See Self::can_subscribe for the chain-verification contract and for why channel_hash is a parameter; this is the PUBLISH-scope counterpart.

Source

pub fn can_subscribe( &self, node_caps: &CapabilitySet, entity_id: &EntityId, channel_hash: ChannelHash, chain: Option<&TokenChain>, revocation: &RevocationRegistry, skew_secs: u64, ) -> bool

Check if entity_id is authorized to subscribe to channel_hash, presenting chain.

When require_token is set, chain must be a TokenChain that (a) roots at one of Self::token_roots, (b) is bound at its leaf to entity_id (the AEAD-verified presenter), and (c) authorizes SUBSCRIBE on channel_hash at every link with no link revoked. A missing chain, an empty token_roots, or a chain that fails verification all reject — fail closed.

§Why channel_hash is a parameter

It is the hash of the channel the caller actually asked for, NOT self.channel_id.hash(). Those coincide for an exact-match config, but a prefix-registered config’s channel_id is a sentinel that insert_prefix itself documents as “not used for hash lookups” — and verifying against it meant a token minted for the sentinel authorized every channel under the prefix, silently degrading a per-channel binding to a per-prefix one. Taking the channel explicitly also removes the standing temptation to reuse one config across many channels and get a gate that answers about the wrong one.

Source

pub fn reverify_subscribe( &self, chain: &TokenChain, entity_id: &EntityId, channel_hash: ChannelHash, revocation: &RevocationRegistry, skew_secs: u64, ) -> bool

Re-verify a previously-presented SUBSCRIBE chain for channel_hash against the current clock + revocation floors, anchored to this channel’s roots. Shared by the periodic expiry sweep and the publish-time re-check so the root-anchoring contract (which roots, which action, which channel hash) lives in exactly one place instead of being re-threaded at each call site — where it had already started to diverge (token_roots vs. an unwrap_or(&[]) fallback).

channel_hash is the requested channel’s — see Self::can_subscribe. Passing the config’s own hash here is what made prefix-registered channels retain a chain under the sentinel key that the publish path (keyed on the real channel) could never find, so every such subscriber was accepted and then revoked before its first delivery.

Source

pub fn reverify_subscribe_presigned( &self, chain: &TokenChain, entity_id: &EntityId, channel_hash: ChannelHash, revocation: &RevocationRegistry, skew_secs: u64, ) -> bool

Like Self::reverify_subscribe but skips the per-link ed25519 signature verification — for callers re-checking a chain whose signatures already verified once (immutable tokens). Time bounds, revocation, anchoring, and scope are still re-checked. See TokenChain::verify_authorizes_presigned.

Trait Implementations§

Source§

impl Clone for ChannelConfig

Source§

fn clone(&self) -> ChannelConfig

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ChannelConfig

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more