1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use crate::registry::RecordId;
use core::fmt;
use indexmap::IndexSet;
use serde::{Deserialize, Serialize};
use std::{str::FromStr, time::SystemTime};
use warg_crypto::hash::{AnyHash, HashAlgorithm};
use warg_crypto::signing;

/// An operator record is a collection of entries published together by the same author
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OperatorRecord {
    /// The hash of the previous operator record envelope
    pub prev: Option<RecordId>,
    /// The version of the registry protocol used
    pub version: u32,
    /// When this record was published
    pub timestamp: SystemTime,
    /// The entries being published in this record
    pub entries: Vec<OperatorEntry>,
}

impl crate::Record for OperatorRecord {
    fn contents(&self) -> IndexSet<&AnyHash> {
        Default::default()
    }
}

/// Each permission represents the ability to use the specified entry
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub enum Permission {
    /// Permission to sign checkpoints.
    Commit,
    /// Permission to define namespace in operator log.
    DefineNamespace,
    /// Permission to import namespace from another registry and add to the operator log.
    ImportNamespace,
}

impl Permission {
    /// Gets an array of all permissions.
    pub const fn all() -> [Permission; 3] {
        [
            Permission::Commit,
            Permission::DefineNamespace,
            Permission::ImportNamespace,
        ]
    }
}

impl fmt::Display for Permission {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Permission::Commit => write!(f, "commit"),
            Permission::DefineNamespace => write!(f, "defineNamespace"),
            Permission::ImportNamespace => write!(f, "importNamespace"),
        }
    }
}

impl FromStr for Permission {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "commit" => Ok(Permission::Commit),
            "defineNamespace" => Ok(Permission::DefineNamespace),
            "importNamespace" => Ok(Permission::ImportNamespace),
            _ => Err(()),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum OperatorEntry {
    /// Initializes a operator log.
    /// Must be the first entry of every log and not appear elsewhere.
    Init {
        /// The hash algorithm this log will use for linking
        hash_algorithm: HashAlgorithm,
        /// The original operator key
        key: signing::PublicKey,
    },
    /// Grant the specified key a permission.
    /// The author of this entry must have the permission.
    GrantFlat {
        key: signing::PublicKey,
        permissions: Vec<Permission>,
    },
    /// Remove a permission from a key.
    /// The author of this entry must have the permission.
    RevokeFlat {
        key_id: signing::KeyID,
        permissions: Vec<Permission>,
    },
    /// The registry defines a namespace to be used in its own package logs.
    DefineNamespace { namespace: String },
    /// The registry defines a namespace as imported from another registry.
    ImportNamespace { namespace: String, registry: String },
}

impl OperatorEntry {
    /// Check permission is required to submit this entry
    pub fn required_permission(&self) -> Option<Permission> {
        match self {
            Self::Init { .. } => None,
            Self::GrantFlat { .. } | Self::RevokeFlat { .. } => Some(Permission::Commit),
            Self::DefineNamespace { .. } => Some(Permission::DefineNamespace),
            Self::ImportNamespace { .. } => Some(Permission::ImportNamespace),
        }
    }
}