noosphere_core/authority/
authorization.rs1use std::{convert::TryFrom, fmt::Display, str::FromStr};
2
3use anyhow::{anyhow, Result};
4use cid::Cid;
5use libipld_core::{ipld::Ipld, raw::RawCodec};
6use noosphere_storage::block_encode;
7use ucan::{chain::ProofChain, crypto::did::DidParser, store::UcanJwtStore, Ucan};
8
9#[cfg(doc)]
10use ucan::ipld::UcanIpld;
11
12#[cfg(doc)]
13use crate::data::Jwt;
14
15use super::SUPPORTED_KEYS;
16
17#[derive(Clone, Debug)]
25pub enum Authorization {
26 Ucan(Ucan),
28 Cid(Cid),
31}
32
33impl Authorization {
34 pub async fn as_ucan<S: UcanJwtStore>(&self, store: &S) -> Result<Ucan> {
37 match self {
38 Authorization::Ucan(ucan) => Ok(ucan.clone()),
39 Authorization::Cid(cid) => Ucan::from_str(&store.require_token(cid).await?),
40 }
41 }
42
43 pub async fn as_proof_chain<S: UcanJwtStore>(&self, store: &S) -> Result<ProofChain> {
45 let mut did_parser = DidParser::new(SUPPORTED_KEYS);
46 Ok(match self {
47 Authorization::Ucan(ucan) => {
48 ProofChain::from_ucan(ucan.clone(), None, &mut did_parser, store).await?
49 }
50 Authorization::Cid(cid) => {
51 ProofChain::from_cid(cid, None, &mut did_parser, store).await?
52 }
53 })
54 }
55}
56
57impl FromStr for Authorization {
58 type Err = anyhow::Error;
59
60 fn from_str(s: &str) -> Result<Self, Self::Err> {
61 let mut parts = s.trim().split(':');
62 Ok(match parts.next() {
63 Some("jwt") => Authorization::Ucan(Ucan::from_str(
64 parts.next().ok_or_else(|| anyhow!("Missing token"))?,
65 )?),
66 Some("cid") => Authorization::Cid(Cid::try_from(
67 parts.next().ok_or_else(|| anyhow!("Missing CID string"))?,
68 )?),
69 Some(any_other) => Authorization::Cid(Cid::from_str(any_other)?),
70 None => return Err(anyhow!("Authorization had empty value")),
71 })
72 }
73}
74
75impl From<Cid> for Authorization {
76 fn from(cid: Cid) -> Self {
77 Authorization::Cid(cid)
78 }
79}
80
81impl TryFrom<Authorization> for Cid {
82 type Error = anyhow::Error;
83
84 fn try_from(value: Authorization) -> Result<Self, Self::Error> {
85 Cid::try_from(&value)
86 }
87}
88
89impl TryFrom<&Authorization> for Cid {
90 type Error = anyhow::Error;
91
92 fn try_from(value: &Authorization) -> Result<Self, Self::Error> {
93 Ok(match value {
94 Authorization::Ucan(ucan) => {
95 let jwt = ucan.encode()?;
96 let (cid, _) = block_encode::<RawCodec, _>(&Ipld::Bytes(jwt.as_bytes().to_vec()))?;
97 cid
98 }
99 Authorization::Cid(cid) => *cid,
100 })
101 }
102}
103
104impl Display for Authorization {
105 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106 let cid = Cid::try_from(self).map_err(|_| std::fmt::Error)?;
107 cid.fmt(f)
108 }
109}