Skip to content

Commit b2286c5

Browse files
authored
Merge pull request #30 from koivunej/cbor_serde_cid
Fix cbor cid serde
2 parents f6bb3b2 + 1c50b36 commit b2286c5

File tree

6 files changed

+73
-3
lines changed

6 files changed

+73
-3
lines changed

Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dag-cbor/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ thiserror = "1.0.14"
1515
[dev-dependencies]
1616
libipld-macro = { path = "../macro" }
1717
multihash = "0.10.1"
18+
hex = "0.4.2"

dag-cbor/src/decode.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,17 @@ pub fn read_link<R: Read>(r: &mut R) -> Result<Cid> {
105105
return Err(CborError::UnknownTag);
106106
}
107107
let len = read_u8(r)?;
108+
if len == 0 {
109+
return Err(CborError::LengthOutOfRange);
110+
}
108111
let bytes = read_bytes(r, len as usize)?;
109-
Ok(Cid::try_from(bytes)?)
112+
if bytes[0] != 0 {
113+
return Err(CborError::InvalidCidPrefix(bytes[0]));
114+
}
115+
116+
// skip the first byte per
117+
// https://github.com/ipld/specs/blob/master/block-layer/codecs/dag-cbor.md#links
118+
Ok(Cid::try_from(&bytes[1..])?)
110119
}
111120

112121
pub trait ReadCbor: Sized {

dag-cbor/src/encode.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,11 @@ impl WriteCbor for Cid {
218218
#[inline]
219219
fn write_cbor<W: Write>(&self, w: &mut W) -> Result<()> {
220220
write_tag(w, 42)?;
221+
// insert zero byte per https://github.com/ipld/specs/blob/master/block-layer/codecs/dag-cbor.md#links
221222
let bytes = self.to_bytes();
222-
bytes.as_slice().write_cbor(w)?;
223+
write_u64(w, 2, (bytes.len() + 1) as u64)?;
224+
w.write_all(&[0])?;
225+
w.write_all(&bytes)?;
223226
Ok(())
224227
}
225228
}

dag-cbor/src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ pub enum CborError {
3939
/// Number larger than u64.
4040
#[error("Number larger than u64.")]
4141
NumberOutOfRange,
42-
/// Length larger than usize.
42+
/// Length larger than usize or too small, for example zero length cid field.
4343
#[error("Length out of range.")]
4444
LengthOutOfRange,
4545
/// Unexpected cbor code.
@@ -60,6 +60,9 @@ pub enum CborError {
6060
/// Utf8 error.
6161
#[error("{0}")]
6262
Utf8(#[from] std::str::Utf8Error),
63+
/// The byte before Cid was not multibase identity prefix.
64+
#[error("Invalid Cid prefix: {0}")]
65+
InvalidCidPrefix(u8),
6366
/// Cid error.
6467
#[error("{0}")]
6568
Cid(#[from] cid::Error),

dag-cbor/tests/roundtrip.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
use dag_cbor::{CborError, DagCborCodec};
2+
use libipld_base::codec::Codec;
3+
4+
#[test]
5+
fn roundtrip_with_cid() {
6+
// generated with go-ipfs
7+
// $ echo foobar > file1
8+
// $ ipfs add foobar
9+
// QmRgutAxd8t7oGkSm4wmeuByG6M51wcTso6cubDdQtuEfL
10+
// $ echo -n '{ "foo": { "/": "QmRgutAxd8t7oGkSm4wmeuByG6M51wcTso6cubDdQtuEfL" } }' \
11+
// | ipfs dag put
12+
// bafyreibvjvcv745gig4mvqs4hctx4zfkono4rjejm2ta6gtyzkqxfjeily
13+
// $ ipfs block get bafyreibvjvcv745gig4mvqs4hctx4zfkono4rjejm2ta6gtyzkqxfjeily \
14+
// | xxd -ps | paste -s --delimiters=
15+
16+
let input =
17+
"a163666f6fd82a582300122031c3d57080d8463a3c63b2923df5a1d40ad7a73eae5a14af584213e5f504ac33";
18+
let input = hex::decode(input).unwrap();
19+
20+
let ipld = DagCborCodec::decode(&input).unwrap();
21+
let bytes = DagCborCodec::encode(&ipld).unwrap().to_vec();
22+
23+
assert_eq!(input, bytes);
24+
}
25+
26+
#[test]
27+
fn invalid_cid_prefix() {
28+
let input =
29+
"a163666f6fd82a582301122031c3d57080d8463a3c63b2923df5a1d40ad7a73eae5a14af584213e5f504ac33";
30+
let input = hex::decode(input).unwrap();
31+
32+
match DagCborCodec::decode(&input).unwrap_err() {
33+
CborError::InvalidCidPrefix(1) => {}
34+
x => panic!("unexpected error: {:?}", x),
35+
}
36+
}
37+
38+
#[test]
39+
fn zero_length_cid() {
40+
let input = "a163666f6fd82a5800";
41+
let input = hex::decode(input).unwrap();
42+
43+
match DagCborCodec::decode(&input).unwrap_err() {
44+
CborError::LengthOutOfRange => {}
45+
x => panic!("unexpected error: {:?}", x),
46+
}
47+
}

0 commit comments

Comments
 (0)