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, Developer = 2, Moderator = 3, Admin = 4, System = 5, NonUser = 6, Collector = 7, 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}