ssi_security/
multibase.rs

1use core::fmt;
2use linked_data::{
3    rdf_types::{
4        dataset::PatternMatchingDataset,
5        interpretation::{ReverseIriInterpretation, ReverseLiteralInterpretation},
6        vocabulary::{IriVocabularyMut, LiteralVocabulary},
7        Interpretation, LiteralType, LiteralTypeRef, Vocabulary, RDF_LANG_STRING,
8    },
9    Context, FromLinkedDataError, LinkedDataDeserializeSubject, LinkedDataPredicateObjects,
10    LinkedDataSubject, RdfLiteral,
11};
12use serde::{Deserialize, Serialize};
13use std::{borrow::Borrow, ops::Deref, str::FromStr};
14
15pub use multibase::{Base, Error};
16
17use crate::MULTIBASE;
18
19#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
20#[serde(transparent)]
21#[repr(transparent)]
22pub struct Multibase(str);
23
24impl Multibase {
25    pub fn new(value: &str) -> &Self {
26        unsafe { std::mem::transmute(value) }
27    }
28
29    pub fn as_str(&self) -> &str {
30        &self.0
31    }
32
33    pub fn decode(&self) -> Result<(Base, Vec<u8>), Error> {
34        multibase::decode(self)
35    }
36}
37
38impl AsRef<str> for Multibase {
39    fn as_ref(&self) -> &str {
40        &self.0
41    }
42}
43
44impl fmt::Display for Multibase {
45    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46        self.0.fmt(f)
47    }
48}
49
50impl<V: Vocabulary, I: Interpretation> linked_data::LinkedDataResource<I, V> for Multibase
51where
52    V: IriVocabularyMut,
53{
54    fn interpretation(
55        &self,
56        vocabulary: &mut V,
57        _interpretation: &mut I,
58    ) -> linked_data::ResourceInterpretation<I, V> {
59        use linked_data::{rdf_types::Term, CowRdfTerm, ResourceInterpretation};
60        ResourceInterpretation::Uninterpreted(Some(CowRdfTerm::Owned(Term::Literal(
61            RdfLiteral::Any(
62                self.0.to_owned(),
63                LiteralType::Any(vocabulary.insert(MULTIBASE)),
64            ),
65        ))))
66    }
67}
68
69impl<V: Vocabulary, I: Interpretation> LinkedDataPredicateObjects<I, V> for Multibase
70where
71    V: IriVocabularyMut,
72{
73    fn visit_objects<S>(&self, mut visitor: S) -> Result<S::Ok, S::Error>
74    where
75        S: linked_data::PredicateObjectsVisitor<I, V>,
76    {
77        visitor.object(self)?;
78        visitor.end()
79    }
80}
81
82impl<V: Vocabulary, I: Interpretation> LinkedDataSubject<I, V> for Multibase {
83    fn visit_subject<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
84    where
85        S: linked_data::SubjectVisitor<I, V>,
86    {
87        visitor.end()
88    }
89}
90
91#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
92#[serde(transparent)]
93#[repr(transparent)]
94pub struct MultibaseBuf(String);
95
96impl MultibaseBuf {
97    pub fn new(value: String) -> Self {
98        Self(value)
99    }
100
101    pub fn encode(base: Base, input: impl AsRef<[u8]>) -> Self {
102        Self(multibase::encode(base, input))
103    }
104
105    pub fn as_multibase(&self) -> &Multibase {
106        Multibase::new(self.0.as_str())
107    }
108}
109
110impl Borrow<str> for MultibaseBuf {
111    fn borrow(&self) -> &str {
112        self.as_str()
113    }
114}
115
116impl Borrow<Multibase> for MultibaseBuf {
117    fn borrow(&self) -> &Multibase {
118        self.as_multibase()
119    }
120}
121
122impl FromStr for MultibaseBuf {
123    type Err = std::convert::Infallible;
124
125    fn from_str(s: &str) -> Result<Self, Self::Err> {
126        Ok(Self(s.to_owned())) // TODO actually parse
127    }
128}
129
130impl AsRef<str> for MultibaseBuf {
131    fn as_ref(&self) -> &str {
132        self.as_str()
133    }
134}
135
136impl Deref for MultibaseBuf {
137    type Target = Multibase;
138
139    fn deref(&self) -> &Self::Target {
140        self.as_multibase()
141    }
142}
143
144impl fmt::Display for MultibaseBuf {
145    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
146        self.0.fmt(f)
147    }
148}
149
150impl<V: Vocabulary, I: Interpretation> linked_data::LinkedDataResource<I, V> for MultibaseBuf
151where
152    V: IriVocabularyMut,
153{
154    fn interpretation(
155        &self,
156        vocabulary: &mut V,
157        _interpretation: &mut I,
158    ) -> linked_data::ResourceInterpretation<I, V> {
159        use linked_data::{rdf_types::Term, CowRdfTerm, ResourceInterpretation};
160        ResourceInterpretation::Uninterpreted(Some(CowRdfTerm::Owned(Term::Literal(
161            RdfLiteral::Any(
162                self.0.to_owned(),
163                LiteralType::Any(vocabulary.insert(MULTIBASE)),
164            ),
165        ))))
166    }
167}
168
169impl<V: Vocabulary, I: Interpretation> LinkedDataPredicateObjects<I, V> for MultibaseBuf
170where
171    V: IriVocabularyMut,
172{
173    fn visit_objects<S>(&self, mut visitor: S) -> Result<S::Ok, S::Error>
174    where
175        S: linked_data::PredicateObjectsVisitor<I, V>,
176    {
177        visitor.object(self)?;
178        visitor.end()
179    }
180}
181
182impl<V: Vocabulary, I: Interpretation> LinkedDataSubject<I, V> for MultibaseBuf {
183    fn visit_subject<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
184    where
185        S: linked_data::SubjectVisitor<I, V>,
186    {
187        visitor.end()
188    }
189}
190
191impl<V: Vocabulary, I> LinkedDataDeserializeSubject<I, V> for MultibaseBuf
192where
193    V: LiteralVocabulary,
194    I: ReverseIriInterpretation<Iri = V::Iri> + ReverseLiteralInterpretation<Literal = V::Literal>,
195{
196    fn deserialize_subject_in<D>(
197        vocabulary: &V,
198        interpretation: &I,
199        _dataset: &D,
200        _graph: Option<&I::Resource>,
201        resource: &<I as Interpretation>::Resource,
202        context: Context<I>,
203    ) -> Result<Self, linked_data::FromLinkedDataError>
204    where
205        D: PatternMatchingDataset<Resource = I::Resource>,
206    {
207        let mut literal_ty = None;
208        for l in interpretation.literals_of(resource) {
209            let l = vocabulary.literal(l).unwrap();
210            match l.type_ {
211                LiteralTypeRef::Any(ty_iri) => {
212                    let ty_iri = vocabulary.iri(ty_iri).unwrap();
213                    if ty_iri == MULTIBASE {
214                        return match l.value.parse() {
215                            Ok(value) => Ok(value),
216                            Err(_) => Err(FromLinkedDataError::InvalidLiteral(
217                                context.into_iris(vocabulary, interpretation),
218                            )),
219                        };
220                    }
221
222                    literal_ty = Some(ty_iri)
223                }
224                LiteralTypeRef::LangString(_) => literal_ty = Some(RDF_LANG_STRING),
225            }
226        }
227
228        match literal_ty {
229            Some(ty) => Err(FromLinkedDataError::LiteralTypeMismatch {
230                context: context.into_iris(vocabulary, interpretation),
231                expected: Some(MULTIBASE.to_owned()),
232                found: ty.to_owned(),
233            }),
234            None => Err(FromLinkedDataError::ExpectedLiteral(
235                context.into_iris(vocabulary, interpretation),
236            )),
237        }
238    }
239}