warg_protocol/operator/
model.rs

1use crate::registry::RecordId;
2use core::fmt;
3use indexmap::IndexSet;
4use serde::{Deserialize, Serialize};
5use std::{str::FromStr, time::SystemTime};
6use warg_crypto::hash::{AnyHash, HashAlgorithm};
7use warg_crypto::signing;
8
9/// An operator record is a collection of entries published together by the same author
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct OperatorRecord {
12    /// The hash of the previous operator record envelope
13    pub prev: Option<RecordId>,
14    /// The version of the registry protocol used
15    pub version: u32,
16    /// When this record was published
17    pub timestamp: SystemTime,
18    /// The entries being published in this record
19    pub entries: Vec<OperatorEntry>,
20}
21
22impl crate::Record for OperatorRecord {
23    fn contents(&self) -> IndexSet<&AnyHash> {
24        Default::default()
25    }
26}
27
28/// Each permission represents the ability to use the specified entry
29#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)]
30#[serde(rename_all = "camelCase")]
31#[non_exhaustive]
32pub enum Permission {
33    /// Permission to sign checkpoints.
34    Commit,
35    /// Permission to define namespace in operator log.
36    DefineNamespace,
37    /// Permission to import namespace from another registry and add to the operator log.
38    ImportNamespace,
39}
40
41impl Permission {
42    /// Gets an array of all permissions.
43    pub const fn all() -> [Permission; 3] {
44        [
45            Permission::Commit,
46            Permission::DefineNamespace,
47            Permission::ImportNamespace,
48        ]
49    }
50}
51
52impl fmt::Display for Permission {
53    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54        match self {
55            Permission::Commit => write!(f, "commit"),
56            Permission::DefineNamespace => write!(f, "defineNamespace"),
57            Permission::ImportNamespace => write!(f, "importNamespace"),
58        }
59    }
60}
61
62impl FromStr for Permission {
63    type Err = ();
64
65    fn from_str(s: &str) -> Result<Self, Self::Err> {
66        match s {
67            "commit" => Ok(Permission::Commit),
68            "defineNamespace" => Ok(Permission::DefineNamespace),
69            "importNamespace" => Ok(Permission::ImportNamespace),
70            _ => Err(()),
71        }
72    }
73}
74
75#[derive(Debug, Clone, PartialEq, Eq)]
76#[non_exhaustive]
77pub enum OperatorEntry {
78    /// Initializes a operator log.
79    /// Must be the first entry of every log and not appear elsewhere.
80    Init {
81        /// The hash algorithm this log will use for linking
82        hash_algorithm: HashAlgorithm,
83        /// The original operator key
84        key: signing::PublicKey,
85    },
86    /// Grant the specified key a permission.
87    /// The author of this entry must have the permission.
88    GrantFlat {
89        key: signing::PublicKey,
90        permissions: Vec<Permission>,
91    },
92    /// Remove a permission from a key.
93    /// The author of this entry must have the permission.
94    RevokeFlat {
95        key_id: signing::KeyID,
96        permissions: Vec<Permission>,
97    },
98    /// The registry defines a namespace to be used in its own package logs.
99    DefineNamespace { namespace: String },
100    /// The registry defines a namespace as imported from another registry.
101    ImportNamespace { namespace: String, registry: String },
102}
103
104impl OperatorEntry {
105    /// Check permission is required to submit this entry
106    pub fn required_permission(&self) -> Option<Permission> {
107        match self {
108            Self::Init { .. } => None,
109            Self::GrantFlat { .. } | Self::RevokeFlat { .. } => Some(Permission::Commit),
110            Self::DefineNamespace { .. } => Some(Permission::DefineNamespace),
111            Self::ImportNamespace { .. } => Some(Permission::ImportNamespace),
112        }
113    }
114}