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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
use anyhow::Result;
use cid::Cid;
use libipld_cbor::DagCborCodec;
use noosphere_storage::BlockStore;
use serde::{Deserialize, Serialize};
use std::{convert::TryFrom, fmt::Display, ops::Deref};
use ucan::{store::UcanJwtStore, Ucan};
use super::{Did, IdentitiesIpld, Jwt, Link};
#[cfg(docs)]
use crate::data::SphereIpld;
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize, Hash)]
pub struct AddressBookIpld {
pub identities: Link<IdentitiesIpld>,
}
impl AddressBookIpld {
pub async fn empty<S: BlockStore>(store: &mut S) -> Result<Self> {
let identities_ipld = IdentitiesIpld::empty(store).await?;
let identities = store.save::<DagCborCodec, _>(identities_ipld).await?.into();
Ok(AddressBookIpld { identities })
}
}
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize, Hash)]
pub struct IdentityIpld {
pub did: Did,
pub link_record: Option<Link<LinkRecord>>,
}
impl IdentityIpld {
pub async fn link_record<S: UcanJwtStore>(&self, store: &S) -> Option<LinkRecord> {
match &self.link_record {
Some(cid) => store
.read_token(cid)
.await
.unwrap_or(None)
.map(|jwt| LinkRecord(jwt.into())),
_ => None,
}
}
}
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize, Hash)]
#[serde(from = "Jwt", into = "Jwt")]
#[repr(transparent)]
pub struct LinkRecord(Jwt);
impl LinkRecord {
pub async fn dereference(&self) -> Option<Cid> {
let token = &self.0;
let ucan = match Ucan::try_from(token.to_string()) {
Ok(ucan) => ucan,
_ => return None,
};
let facts = ucan.facts();
for fact in facts {
match fact.as_object() {
Some(fields) => match fields.get("link") {
Some(cid_string) => {
match Cid::try_from(cid_string.as_str().unwrap_or_default()) {
Ok(cid) => return Some(cid),
Err(error) => {
warn!(
"Could not parse '{}' as name record link: {}",
cid_string, error
);
continue;
}
}
}
None => {
warn!("No 'link' field in fact, skipping...");
continue;
}
},
None => {
warn!("Fact is not an object, skipping...");
continue;
}
}
}
warn!("No facts contained a link!");
None
}
}
impl Deref for LinkRecord {
type Target = Jwt;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Display for LinkRecord {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl From<Jwt> for LinkRecord {
fn from(value: Jwt) -> Self {
LinkRecord(value)
}
}
impl Into<Jwt> for LinkRecord {
fn into(self) -> Jwt {
self.0
}
}