1#[cfg(test)]
2use cid::multibase::Base;
3use cid::{multibase, Cid};
4#[cfg(test)]
5use frame_support::assert_ok;
6use frame_support::ensure;
7use sp_io::hashing::sha2_256;
8use sp_runtime::Vec;
9
10pub type Multihash = cid::multihash::Multihash<64>;
12
13const SHA2_256: u64 = 0x12;
15const BLAKE3: u64 = 0x1e;
17
18const DSNP_HASH_ALGORITHMS: &[u64] = &[SHA2_256, BLAKE3];
20
21const RAW: u64 = 0x55;
23
24#[derive(Debug, PartialEq)]
26pub enum CidError {
27 UnsupportedCidVersion,
29 UnsupportedCidMultihash,
31 MultibaseDecodeError,
33 Utf8DecodeError,
35 InvalidCid,
37}
38
39pub fn compute_cid_v1(bytes: &[u8]) -> Option<Vec<u8>> {
41 let digest = sha2_256(bytes);
42 let mh = Multihash::wrap(SHA2_256, &digest).ok()?;
43 let cid = Cid::new_v1(RAW, mh);
44 Some(cid.to_bytes())
45}
46
47pub fn validate_cid(in_cid: &[u8]) -> Result<Vec<u8>, CidError> {
49 let cid_str: &str = core::str::from_utf8(in_cid).map_err(|_| CidError::Utf8DecodeError)?;
51 ensure!(cid_str.len() > 2, CidError::InvalidCid);
52 ensure!(!cid_str.starts_with("Qm"), CidError::UnsupportedCidVersion);
54
55 let cid_b = multibase::decode(cid_str).map_err(|_| CidError::MultibaseDecodeError)?.1;
57 let cid = Cid::read_bytes(&cid_b[..]).map_err(|_| CidError::InvalidCid)?;
58 ensure!(DSNP_HASH_ALGORITHMS.contains(&cid.hash().code()), CidError::UnsupportedCidMultihash);
59
60 Ok(cid_b)
61}
62
63#[cfg(test)]
64const DUMMY_CID_SHA512: &str = "bafkrgqb76pscorjihsk77zpyst3p364zlti6aojlu4nga34vhp7t5orzwbwwytvp7ej44r5yhjzneanqwb5arcnvuvfwo2d4qgzyx5hymvto4";
65#[cfg(test)]
66const DUMMY_CID_SHA256: &str = "bagaaierasords4njcts6vs7qvdjfcvgnume4hqohf65zsfguprqphs3icwea";
67#[cfg(test)]
68const DUMMY_CID_BLAKE3: &str = "bafkr4ihn4xalcdzoyslzy2nvf5q6il7vwqjvdhhatpqpctijrxh6l5xzru";
69
70#[test]
71fn validate_cid_invalid_utf8_errors() {
72 let bad_cid = vec![0xfc, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1];
73 assert_eq!(
74 validate_cid(&bad_cid).expect_err("Expected Utf8DecodeError"),
75 CidError::Utf8DecodeError
76 );
77}
78
79#[test]
80fn validate_cid_too_short_errors() {
81 let bad_cid = "a".as_bytes().to_vec();
82 assert_eq!(validate_cid(&bad_cid).expect_err("Expected InvalidCid"), CidError::InvalidCid);
83}
84
85#[test]
86fn validate_cid_v0_errors() {
87 let bad_cid = "Qmxxx".as_bytes().to_vec();
88 assert_eq!(
89 validate_cid(&bad_cid).expect_err("Expected UnsupportedCidVersion"),
90 CidError::UnsupportedCidVersion
91 );
92}
93
94#[test]
95fn validate_cid_invalid_multibase_errors() {
96 let bad_cid = "aaaa".as_bytes().to_vec();
97 assert_eq!(
98 validate_cid(&bad_cid).expect_err("Expected MultibaseDecodeError"),
99 CidError::MultibaseDecodeError
100 );
101}
102
103#[test]
104fn validate_cid_invalid_cid_errors() {
105 let bad_cid = multibase::encode(Base::Base32Lower, "foo").as_bytes().to_vec();
106 assert_eq!(validate_cid(&bad_cid).expect_err("Expected InvalidCid"), CidError::InvalidCid);
107}
108
109#[test]
110fn validate_cid_valid_cid_sha2_256_succeeds() {
111 let cid = DUMMY_CID_SHA256.as_bytes().to_vec();
112 assert_ok!(validate_cid(&cid));
113}
114
115#[test]
116fn validate_cid_valid_cid_blake3_succeeds() {
117 let cid = DUMMY_CID_BLAKE3.as_bytes().to_vec();
118 assert_ok!(validate_cid(&cid));
119}
120
121#[test]
122fn validate_cid_invalid_hash_function_errors() {
123 let bad_cid = DUMMY_CID_SHA512.as_bytes().to_vec();
124 assert_eq!(
125 validate_cid(&bad_cid).expect_err("Expected UnsupportedCidMultihash"),
126 CidError::UnsupportedCidMultihash
127 );
128}
129#[test]
130fn validate_cid_not_valid_multibase() {
131 let bad_cid = vec![55, 197, 136, 0, 0, 0, 0, 0, 0, 0, 0];
133 assert_eq!(
134 validate_cid(&bad_cid).expect_err("Expected MultibaseDecodeError"),
135 CidError::MultibaseDecodeError
136 );
137}
138
139#[test]
140fn validate_cid_not_correct_format_errors() {
141 let bad_cid = vec![0, 1, 0, 1, 203, 155, 0, 0, 0, 5, 67];
143 assert_eq!(validate_cid(&bad_cid).expect_err("Expected InvalidCid"), CidError::InvalidCid);
144
145 let another_bad_cid = vec![241, 0, 0, 0, 0, 0, 128, 132, 132, 132, 58];
147 assert_eq!(
148 validate_cid(&another_bad_cid).expect_err("Expected Utf8DecodeError"),
149 CidError::Utf8DecodeError
150 );
151}
152
153#[test]
154fn validate_cid_unwrap_errors() {
155 let bad_cid = vec![102, 70, 70, 70, 70, 70, 70, 70, 70, 48, 48, 48, 54, 53, 53, 48, 48];
157 assert_eq!(validate_cid(&bad_cid).expect_err("Expected InvalidCid"), CidError::InvalidCid);
158}