warg_server/policy/content/
mod.rs

1//! Module for server content policy implementations.
2use thiserror::Error;
3use warg_crypto::hash::AnyHash;
4
5mod wasm;
6
7pub use wasm::*;
8
9/// Represents a content policy error.
10#[derive(Debug, Error)]
11pub enum ContentPolicyError {
12    /// The policy rejected the content with the given message.
13    #[error("content was rejected by policy: {0}")]
14    Rejection(String),
15}
16
17/// The result type returned by content policies.
18pub type ContentPolicyResult<T> = Result<T, ContentPolicyError>;
19
20/// A trait implemented by content policies.
21pub trait ContentPolicy: Send + Sync {
22    /// Creates a new stream policy for the given digest.
23    ///
24    /// The digest is provided so that a policy can make decisions
25    /// based on the content's digest before any content is received.
26    ///
27    /// Upon success, returns a content stream policy that can be used
28    /// to check the content as it is received.
29    fn new_stream_policy(
30        &self,
31        digest: &AnyHash,
32    ) -> ContentPolicyResult<Box<dyn ContentStreamPolicy>>;
33}
34
35/// A trait implemented by content stream policies.
36pub trait ContentStreamPolicy: Send + Sync {
37    /// Checks the given bytes of the content stream.
38    ///
39    /// The bytes represent the next chunk of data received for the
40    /// content stream.
41    fn check(&mut self, bytes: &[u8]) -> ContentPolicyResult<()>;
42
43    /// Called when the content stream has finished.
44    ///
45    /// This method is called after all bytes have been received for
46    /// the content stream.
47    fn finalize(&mut self) -> ContentPolicyResult<()>;
48}
49
50/// Represents a collection of content policies.
51///
52/// Content policies are checked in order of their addition
53/// to the collection.
54#[derive(Default)]
55pub struct ContentPolicyCollection {
56    policies: Vec<Box<dyn ContentPolicy>>,
57}
58
59impl ContentPolicyCollection {
60    /// Creates a new content policy collection.
61    pub fn new() -> Self {
62        Self::default()
63    }
64
65    /// Pushes a new content policy into the collection.
66    pub fn push(&mut self, policy: impl ContentPolicy + 'static) {
67        self.policies.push(Box::new(policy));
68    }
69}
70
71impl ContentPolicy for ContentPolicyCollection {
72    fn new_stream_policy(
73        &self,
74        digest: &AnyHash,
75    ) -> ContentPolicyResult<Box<dyn ContentStreamPolicy>> {
76        Ok(Box::new(ContentStreamPolicyCollection {
77            policies: self
78                .policies
79                .iter()
80                .map(|p| p.new_stream_policy(digest))
81                .collect::<ContentPolicyResult<_>>()?,
82        }))
83    }
84}
85
86pub struct ContentStreamPolicyCollection {
87    policies: Vec<Box<dyn ContentStreamPolicy>>,
88}
89
90impl ContentStreamPolicy for ContentStreamPolicyCollection {
91    fn check(&mut self, bytes: &[u8]) -> ContentPolicyResult<()> {
92        for policy in &mut self.policies {
93            policy.check(bytes)?;
94        }
95
96        Ok(())
97    }
98
99    fn finalize(&mut self) -> ContentPolicyResult<()> {
100        for policy in &mut self.policies {
101            policy.finalize()?;
102        }
103
104        Ok(())
105    }
106}