141 lines
3.9 KiB
Rust
141 lines
3.9 KiB
Rust
use std::collections::HashSet;
|
|
|
|
use radicle::crypto::PublicKey;
|
|
use radicle::node::policy::config::Config;
|
|
use radicle::node::policy::store::Read;
|
|
use radicle::prelude::RepoId;
|
|
|
|
pub use radicle::node::policy::{Policy, Scope, SeedingPolicy};
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub enum Allowed {
|
|
All,
|
|
Followed { remotes: HashSet<PublicKey> },
|
|
}
|
|
|
|
impl Allowed {
|
|
pub fn from_config(rid: RepoId, config: &Config<Read>) -> Result<Self, error::Policy> {
|
|
let entry = config
|
|
.seed_policy(&rid)
|
|
.map_err(|err| error::Policy::FailedPolicy { rid, err })?;
|
|
match entry.policy {
|
|
SeedingPolicy::Block => {
|
|
log::info!("Attempted to fetch non-seeded repo {rid}");
|
|
Err(error::Policy::BlockedPolicy { rid })
|
|
}
|
|
SeedingPolicy::Allow { scope: Scope::All } => Ok(Self::All),
|
|
SeedingPolicy::Allow {
|
|
scope: Scope::Followed,
|
|
} => {
|
|
let nodes = config
|
|
.follow_policies()
|
|
.map_err(|err| error::Policy::FailedNodes { rid, err })?;
|
|
|
|
let mut followed = HashSet::new();
|
|
|
|
for node in nodes {
|
|
let node = match node {
|
|
Ok(policy) => policy,
|
|
Err(err) => {
|
|
log::debug!("Failed to read follow policy for {rid}: {err}");
|
|
continue;
|
|
}
|
|
};
|
|
|
|
if node.policy == Policy::Allow {
|
|
followed.insert(node.nid);
|
|
}
|
|
}
|
|
|
|
Ok(Allowed::Followed { remotes: followed })
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// A set of [`PublicKey`]s to ignore when fetching from a remote.
|
|
#[derive(Clone, Debug)]
|
|
pub struct BlockList(HashSet<PublicKey>);
|
|
|
|
impl FromIterator<PublicKey> for BlockList {
|
|
fn from_iter<T: IntoIterator<Item = PublicKey>>(iter: T) -> Self {
|
|
Self(iter.into_iter().collect())
|
|
}
|
|
}
|
|
|
|
impl Extend<PublicKey> for BlockList {
|
|
fn extend<T: IntoIterator<Item = PublicKey>>(&mut self, iter: T) {
|
|
self.0.extend(iter)
|
|
}
|
|
}
|
|
|
|
impl BlockList {
|
|
pub fn is_blocked(&self, key: &PublicKey) -> bool {
|
|
self.0.contains(key)
|
|
}
|
|
|
|
pub fn from_config(config: &Config<Read>) -> Result<BlockList, error::Blocked> {
|
|
let mut blocked = HashSet::new();
|
|
|
|
for entry in config.follow_policies()? {
|
|
let entry = match entry {
|
|
Ok(entry) => entry,
|
|
Err(err) => {
|
|
log::debug!("Failed to read follow policy: {err}");
|
|
continue;
|
|
}
|
|
};
|
|
|
|
if entry.policy == Policy::Block {
|
|
blocked.insert(entry.nid);
|
|
}
|
|
}
|
|
|
|
Ok(BlockList(blocked))
|
|
}
|
|
}
|
|
|
|
pub mod error {
|
|
use radicle::node::policy;
|
|
use radicle::prelude::RepoId;
|
|
use radicle::storage;
|
|
use thiserror::Error;
|
|
|
|
#[derive(Debug, Error)]
|
|
#[error(transparent)]
|
|
pub struct Blocked(#[from] policy::config::Error);
|
|
|
|
#[derive(Debug, Error)]
|
|
pub enum Policy {
|
|
#[error("failed to find policy for {rid}")]
|
|
FailedPolicy {
|
|
rid: RepoId,
|
|
#[source]
|
|
err: policy::store::Error,
|
|
},
|
|
#[error("cannot fetch {rid} as it is not seeded")]
|
|
BlockedPolicy { rid: RepoId },
|
|
#[error("failed to get followed nodes for {rid}")]
|
|
FailedNodes {
|
|
rid: RepoId,
|
|
#[source]
|
|
err: policy::store::Error,
|
|
},
|
|
|
|
#[error(transparent)]
|
|
Storage(#[from] storage::Error),
|
|
|
|
#[error(transparent)]
|
|
Git(#[from] radicle::git::raw::Error),
|
|
|
|
#[error(transparent)]
|
|
Refs(Box<storage::refs::Error>),
|
|
}
|
|
|
|
impl From<storage::refs::Error> for Policy {
|
|
fn from(err: storage::refs::Error) -> Self {
|
|
Self::Refs(Box::new(err))
|
|
}
|
|
}
|
|
}
|