Skip to content

Commit

Permalink
feat: impl pld support
Browse files Browse the repository at this point in the history
  • Loading branch information
dav1do committed May 20, 2024
1 parent 37a132d commit 10e89b9
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 19 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ libipld = { version = "0.16.0", default-features = false, features = [
] }
libipld-json = { version = "0.16.0", default-features = false, optional = true }
serde = "1.0.152"
serde_json = "1.0.117"
serde_derive = "1.0.152"
serde_ipld_dagcbor = "0.3.0"
thiserror = "1.0.38"
Expand Down
15 changes: 14 additions & 1 deletion src/codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,19 @@ impl TryFrom<Encoded> for JsonWebSignature {
type Error = Error;

fn try_from(value: Encoded) -> Result<Self, Self::Error> {
let link = Cid::try_from(value.payload.as_ref().ok_or(Error::NotJws)?.as_slice())?;
let payload = value.payload.as_ref().ok_or(Error::NotJws)?;

//do we need to parse all the strings as ipfs:// CIDs here and error or can we wait until we encode?
let (link, pld) = match serde_json::from_slice::<serde_json::Value>(payload.as_ref()) {
Ok(json) => {
let res = match crate::JsonPld(json).try_into().map_err(|_| Error::NotJws)? {
Ipld::Map(map) => map,
_ => return Err(Error::NotJws),
};
(None, Some(res))
}
Err(_) => (Some(Cid::try_from(payload.as_ref())?), None),
};
Ok(Self {
payload: value
.payload
Expand All @@ -88,6 +100,7 @@ impl TryFrom<Encoded> for JsonWebSignature {
.map(Signature::from)
.collect(),
link,
pld,
})
}
}
Expand Down
100 changes: 82 additions & 18 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,10 @@ mod error;

use std::{collections::BTreeMap, io::BufReader};

use libipld::codec::{Codec, Decode, Encode};
use libipld::error::UnsupportedCodec;
use libipld::Cid;
use libipld::Ipld;
use libipld::{
codec::{Codec, Decode, Encode},
ipld,
};

use libipld::{Cid, Ipld};
#[cfg(feature = "dag-json")]
use libipld_json::DagJsonCodec;

Expand Down Expand Up @@ -158,21 +155,87 @@ impl Encode<DagJsonCodec> for Jose {
pub struct JsonWebSignature {
/// The payload base64 url encoded.
pub payload: String,

/// The set of signatures.
pub signatures: Vec<Signature>,

/// CID link from the payload.
pub link: Cid,
pub link: Option<Cid>,
/// The json payload with ipfs:// prefixed strings replaced with CIDs.
pub pld: Option<BTreeMap<String, Ipld>>,
}

#[derive(Clone, Debug, PartialEq)]
struct JsonPld(serde_json::Value);

impl TryFrom<JsonPld> for Ipld {
type Error = anyhow::Error;

fn try_from(value: JsonPld) -> Result<Self, Self::Error> {
match value.0 {
serde_json::Value::Null => Ok(Ipld::Null),
serde_json::Value::Bool(b) => Ok(Ipld::Bool(b)),
serde_json::Value::Number(n) => {
if let Some(i) = n.as_i64() {
Ok(Ipld::Integer(i as i128))
} else if let Some(f) = n.as_f64() {
Ok(Ipld::Float(f))
} else {
unreachable!("Number out of range")
}
}
serde_json::Value::String(s) => {
if let Some(str) = s.strip_prefix("ipfs://") {
let cid = Cid::try_from(str)?;
Ok(Ipld::Link(cid))
} else {
Ok(Ipld::String(s))
}
}
serde_json::Value::Array(arr) => {
let list = arr
.into_iter()
.map(|v| JsonPld(v).try_into())
.collect::<Result<Vec<_>, _>>()?;
Ok(Ipld::List(list))
}
serde_json::Value::Object(obj) => {
let map = obj
.into_iter()
.map(|(k, v)| JsonPld(v).try_into().map(|v| (k, v)))
.collect::<Result<BTreeMap<_, _>, _>>()?;
Ok(Ipld::Map(map))
}
}
}
}

impl<'a> From<&'a JsonWebSignature> for Ipld {
fn from(value: &'a JsonWebSignature) -> Self {
ipld!({
"payload": value.payload.to_owned(),
"signatures": value.signatures.iter().map(Ipld::from).collect::<Vec<Ipld>>(),
"link": value.link,
})
impl<'a> TryFrom<&'a JsonWebSignature> for Ipld {
type Error = anyhow::Error;

fn try_from(value: &'a JsonWebSignature) -> Result<Self, Self::Error> {
let mut fields = BTreeMap::new();

fields.insert("payload".to_string(), value.payload.to_owned().into());
fields.insert(
"signatures".to_string(),
Ipld::List(
value
.signatures
.iter()
.map(Ipld::from)
.collect::<Vec<Ipld>>(),
),
);

if let Some(link) = value.link {
fields.insert("link".to_string(), link.into());
}

if let Some(pld) = value.pld.to_owned() {
let data: Ipld = pld.try_into()?;
fields.insert("pld".to_string(), data);
}

Ok(Ipld::Map(fields))
}
}

Expand All @@ -194,7 +257,7 @@ impl Decode<DagJoseCodec> for JsonWebSignature {
#[cfg(feature = "dag-json")]
impl Encode<DagJsonCodec> for JsonWebSignature {
fn encode<W: std::io::Write>(&self, c: DagJsonCodec, w: &mut W) -> anyhow::Result<()> {
let data: Ipld = self.into();
let data: Ipld = self.try_into()?;
data.encode(c, w)
}
}
Expand Down Expand Up @@ -403,7 +466,7 @@ mod tests {
} = fixture_jws();
let (payload_b64, protected_b64, signature_b64) =
fixture_jws_base64(&payload, &protected, &signature);
let link = Cid::try_from(base64_url::decode(&payload_b64).unwrap()).unwrap();
let link = Some(Cid::try_from(base64_url::decode(&payload_b64).unwrap()).unwrap());
assert_roundtrip(
DagJoseCodec,
&JsonWebSignature {
Expand All @@ -417,6 +480,7 @@ mod tests {
signature: signature_b64,
}],
link,
pld: None,
},
&ipld!({
"payload": payload,
Expand Down

0 comments on commit 10e89b9

Please sign in to comment.