timegraph_identity/
apikey.rs

1extern crate anyhow;
2extern crate serde_xdr;
3
4use crate::signer::{Algorithm, PublicKey, Signature, Signer, SIGNING_CONTEXT};
5use crate::{bytes_decode, bytes_encode, Verifier};
6use serde::{Deserialize, Serialize};
7use std::str::FromStr;
8
9#[derive(PartialEq, Debug, Copy, Clone, Serialize, Deserialize, Default)]
10pub enum Role {
11    #[default]
12    User = 1, // can query from user namespace
13    Developer = 2, // + can modify user namespace
14    Moderator = 3, // + can do audit
15    Admin = 4,     // + can grant/revoke role to/from another user
16    System = 5,    // can behave as another user(as a developer maximum)
17    // and do limited system queries
18    NonUser = 6,   // can only create account
19    Collector = 7, // can only collect data
20    TimeGraph = 8,
21}
22
23const USER_ROLE: &str = "user";
24const DEVELOPER_ROLE: &str = "developer";
25const MODERATOR_ROLE: &str = "moderator";
26const ADMIN_ROLE: &str = "admin";
27const SYSTEM_ROLE: &str = "system";
28const NONUSER_ROLE: &str = "nonuser";
29const COLLECTOR_ROLE: &str = "collector";
30const TIMEGRAPH_ROLE: &str = "timegraph";
31
32impl ToString for Role {
33    fn to_string(&self) -> String {
34        self.as_str().to_string()
35    }
36}
37
38impl FromStr for Role {
39    type Err = anyhow::Error;
40
41    fn from_str(s: &str) -> Result<Self, Self::Err> {
42        match s.to_ascii_lowercase().as_str() {
43            USER_ROLE => Ok(Role::User),
44            DEVELOPER_ROLE => Ok(Role::Developer),
45            MODERATOR_ROLE => Ok(Role::Moderator),
46            ADMIN_ROLE => Ok(Role::Admin),
47            SYSTEM_ROLE => Ok(Role::System),
48            COLLECTOR_ROLE => Ok(Role::Collector),
49            TIMEGRAPH_ROLE => Ok(Role::TimeGraph),
50            r => Err(anyhow::anyhow!("unknown role {r}")),
51        }
52    }
53}
54
55impl Role {
56    pub fn as_str(&self) -> &'static str {
57        match self {
58            Role::User => USER_ROLE,
59            Role::Developer => DEVELOPER_ROLE,
60            Role::Moderator => MODERATOR_ROLE,
61            Role::Admin => ADMIN_ROLE,
62            Role::System => SYSTEM_ROLE,
63            Role::NonUser => NONUSER_ROLE,
64            Role::Collector => COLLECTOR_ROLE,
65            Role::TimeGraph => TIMEGRAPH_ROLE,
66        }
67    }
68    pub fn from(role: i16) -> Self {
69        match role {
70            x if x == Self::User as i16 => Self::User,
71            x if x == Self::Developer as i16 => Self::Developer,
72            x if x == Self::Moderator as i16 => Self::Moderator,
73            x if x == Self::Admin as i16 => Self::Admin,
74            x if x == Self::System as i16 => Self::System,
75            x if x == Self::Collector as i16 => Self::Collector,
76            x if x == Self::TimeGraph as i16 => Self::TimeGraph,
77            _ => Self::NonUser,
78        }
79    }
80
81    pub fn isa(self, role: Role) -> bool {
82        use Role::*;
83        match (self, role) {
84            (x, y) if x == y => true,
85            (Developer, User) => true,
86            (Moderator, User | Developer) => true,
87            (Admin, User | Developer | Moderator) => true,
88            (TimeGraph, User | Developer | Moderator | Admin) => true,
89            _ => false,
90        }
91    }
92
93    pub fn try_be_a(self, role: Role) -> anyhow::Result<Role> {
94        if self.isa(role) {
95            Ok(role)
96        } else {
97            Err(anyhow::anyhow!(
98                "{} cannot be a {}",
99                self.as_str(),
100                role.as_str()
101            ))
102        }
103    }
104}
105
106#[derive(Clone)]
107pub struct ApiKey(Signer);
108
109impl ApiKey {
110    pub fn from_secret(secret: &str) -> anyhow::Result<Self> {
111        Ok(ApiKey(Signer::from_bytes(&bytes_decode(secret)?)?))
112    }
113
114    pub fn new() -> anyhow::Result<Self> {
115        Ok(ApiKey(Signer::new()?))
116    }
117
118    pub fn certify(&self, role: Role, owner: &Signer) -> anyhow::Result<Cert> {
119        Cert::certify(owner, self.0.public_key(), role)
120    }
121
122    pub fn build(&self, role: Role, owner: &PublicKey) -> anyhow::Result<Vec<u8>> {
123        Cert::build(owner.clone(), self.0.public_key(), role)
124    }
125
126    pub fn key(&self) -> anyhow::Result<String> {
127        bytes_encode(&self.0.public_key().to_bytes())
128    }
129
130    pub fn pubkey_from_str(key: &str) -> anyhow::Result<PublicKey> {
131        Signer::pubkey_from_bytes(&bytes_decode(key)?)
132    }
133
134    pub fn secret(&self) -> anyhow::Result<String> {
135        bytes_encode(&self.0.to_bytes()?)
136    }
137}
138
139#[derive(Clone, Debug)]
140pub struct Cert {
141    pub role: Role,
142    pub owner: PublicKey,
143    pub delegate: PublicKey,
144    pub signature: Option<Signature>,
145}
146
147impl Cert {
148    pub fn from(c: &InternalCert) -> anyhow::Result<Self> {
149        Ok(Self {
150            role: c.r,
151            owner: Signer::pubkey_from_bytes(&c.o)?,
152            delegate: Signer::pubkey_from_bytes(&c.d)?,
153            signature: Some(Signer::signature_from_bytes(&c.s)?),
154        })
155    }
156    pub fn from_bytes(bs: &[u8]) -> anyhow::Result<Self> {
157        let c: InternalCert = serde_xdr::from_bytes(bs)?;
158        Self::from(&c)
159    }
160    pub fn to_bytes(&self) -> anyhow::Result<Vec<u8>> {
161        let c = InternalCert::from(self)?;
162        Ok(serde_xdr::to_bytes(&c)?)
163    }
164
165    pub fn build(owner: PublicKey, delegate: PublicKey, role: Role) -> anyhow::Result<Vec<u8>> {
166        let c = PublicCert::from(&Self {
167            owner,
168            delegate,
169            role,
170            signature: None,
171        })?;
172        Ok(serde_xdr::to_bytes(&c)?)
173    }
174
175    pub fn complete(bs: &[u8], signature: &[u8]) -> anyhow::Result<Self> {
176        let c: PublicCert = serde_xdr::from_bytes(bs)?;
177        Ok(Self {
178            owner: Signer::pubkey_from_bytes(&c.o)?,
179            delegate: Signer::pubkey_from_bytes(&c.d)?,
180            role: c.r,
181            signature: Some(Signature::from_bytes(Algorithm::Sr25519, signature)?),
182        })
183    }
184
185    pub fn new(owner: PublicKey, delegate: PublicKey, role: Role, signature: Signature) -> Self {
186        Self {
187            owner,
188            delegate,
189            role,
190            signature: Some(signature),
191        }
192    }
193
194    pub fn certify(owner: &Signer, delegate: PublicKey, role: Role) -> anyhow::Result<Self> {
195        let mut cert = Self {
196            owner: owner.public_key(),
197            delegate,
198            role,
199            signature: None,
200        };
201        let c = PublicCert::from(&cert)?;
202        let bs = serde_xdr::to_bytes(&c)?;
203        cert.signature = Some(owner.sign_msg(&bs, SIGNING_CONTEXT)?);
204        Ok(cert)
205    }
206
207    pub fn verify(&self) -> anyhow::Result<()> {
208        let c = PublicCert::from(self)?;
209        let bs = serde_xdr::to_bytes(&c)?;
210        let signature = &self.signature.ok_or(anyhow::anyhow!("unsigned"))?;
211        Verifier(self.owner)
212            .verify_msg(&bs, SIGNING_CONTEXT, signature)
213            .or_else(|_| {
214                let bytes_start = b"<Bytes>";
215                let bytes_end = b"</Bytes>";
216                let wrapped_bytes = [&bytes_start[..], &bs[..], &bytes_end[..]].concat();
217                Verifier(self.owner).verify_msg(&wrapped_bytes, SIGNING_CONTEXT, signature)
218            })
219    }
220    pub fn stringify(&self) -> anyhow::Result<String> {
221        let c = InternalCert::from(self)?;
222        bytes_encode(&serde_xdr::to_bytes(&c)?)
223    }
224    pub fn stringify_hex(&self) -> anyhow::Result<String> {
225        let c = InternalCert::from(self)?;
226        Ok(hex::encode(&serde_xdr::to_bytes(&c)?))
227    }
228    pub fn parse(str: &str) -> anyhow::Result<Self> {
229        let c: InternalCert = serde_xdr::from_bytes(&bytes_decode(str)?)?;
230        Ok(Self::from(&c)?)
231    }
232    pub fn verify_str(str: &str) -> anyhow::Result<Self> {
233        let cert = Self::parse(str)?;
234        cert.verify()?;
235        Ok(cert)
236    }
237    pub fn stringify_owner(&self) -> anyhow::Result<String> {
238        bytes_encode(&self.owner.to_bytes())
239    }
240    pub fn stringify_delegate(&self) -> anyhow::Result<String> {
241        bytes_encode(&self.delegate.to_bytes())
242    }
243    pub fn to_json(&self) -> anyhow::Result<String> {
244        let c = InternalCert::from(self)?;
245        Ok(serde_json::to_string_pretty(&c)?)
246    }
247    pub fn owner_address(&self) -> anyhow::Result<String> {
248        Signer::pubkey_to_address(&self.owner)
249    }
250}
251
252#[derive(Clone, Serialize, Deserialize)]
253pub struct InternalCert {
254    r: Role,
255    o: Vec<u8>,
256    d: Vec<u8>,
257    s: Vec<u8>,
258}
259
260impl InternalCert {
261    pub fn from(c: &Cert) -> anyhow::Result<Self> {
262        Ok(Self {
263            r: c.role,
264            o: c.owner.to_bytes(),
265            d: c.delegate.to_bytes(),
266            s: c.signature.ok_or(anyhow::anyhow!("unsigned"))?.to_bytes(),
267        })
268    }
269}
270
271#[derive(Clone, Serialize, Deserialize)]
272pub struct PublicCert {
273    r: Role,
274    o: Vec<u8>,
275    d: Vec<u8>,
276}
277
278impl PublicCert {
279    pub fn from(c: &Cert) -> anyhow::Result<Self> {
280        Ok(Self {
281            r: c.role,
282            o: c.owner.to_bytes(),
283            d: c.delegate.to_bytes(),
284        })
285    }
286}