1use std::{cell::RefCell, fmt::Display, hash::Hash, io, str::FromStr};
6
7use colored::Colorize;
8use sha1::Digest;
9
10use crate::internal::object::types::ObjectType;
11
12#[derive(
16 Clone,
17 Copy,
18 Debug,
19 PartialEq,
20 Eq,
21 Hash,
22 PartialOrd,
23 Ord,
24 Default,
25 serde::Deserialize,
26 serde::Serialize,
27 rkyv::Archive,
28 rkyv::Serialize,
29 rkyv::Deserialize,
30)]
31pub enum HashKind {
32 #[default]
33 Sha1,
34 Sha256,
35}
36impl HashKind {
37 pub const fn size(&self) -> usize {
39 match self {
40 HashKind::Sha1 => 20,
41 HashKind::Sha256 => 32,
42 }
44 }
45 pub const fn hex_len(&self) -> usize {
47 match self {
48 HashKind::Sha1 => 40,
49 HashKind::Sha256 => 64,
50 }
51 }
52 pub const fn as_str(&self) -> &'static str {
54 match self {
55 HashKind::Sha1 => "sha1",
56 HashKind::Sha256 => "sha256",
57 }
58 }
59}
60impl std::fmt::Display for HashKind {
61 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62 f.write_str(self.as_str())
63 }
64}
65impl std::str::FromStr for HashKind {
66 type Err = String;
67
68 fn from_str(s: &str) -> Result<Self, Self::Err> {
69 match s.to_ascii_lowercase().as_str() {
70 "sha1" => Ok(HashKind::Sha1),
71 "sha256" => Ok(HashKind::Sha256),
72 _ => Err("Invalid hash kind".to_string()),
73 }
74 }
75}
76
77#[derive(
78 Clone,
79 Copy,
80 Debug,
81 PartialEq,
82 Eq,
83 Hash,
84 PartialOrd,
85 Ord,
86 serde::Deserialize,
87 serde::Serialize,
88 rkyv::Archive,
89 rkyv::Serialize,
90 rkyv::Deserialize,
91)]
92pub enum ObjectHash {
96 Sha1([u8; 20]),
97 Sha256([u8; 32]),
98}
99impl Default for ObjectHash {
100 fn default() -> Self {
101 ObjectHash::Sha1([0u8; 20])
102 }
103}
104impl Display for ObjectHash {
105 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
106 write!(f, "{}", hex::encode(self.as_ref()))
107 }
108}
109impl AsRef<[u8]> for ObjectHash {
110 fn as_ref(&self) -> &[u8] {
111 match self {
112 ObjectHash::Sha1(bytes) => bytes.as_slice(),
113 ObjectHash::Sha256(bytes) => bytes.as_slice(),
114 }
115 }
116}
117impl FromStr for ObjectHash {
119 type Err = String;
120
121 fn from_str(s: &str) -> Result<Self, Self::Err> {
122 match s.len() {
123 40 => {
124 let mut h = [0u8; 20];
125 let bytes = hex::decode(s).map_err(|e| e.to_string())?;
126 h.copy_from_slice(bytes.as_slice());
127 Ok(ObjectHash::Sha1(h))
128 }
129 64 => {
130 let mut h = [0u8; 32];
131 let bytes = hex::decode(s).map_err(|e| e.to_string())?;
132 h.copy_from_slice(bytes.as_slice());
133 Ok(ObjectHash::Sha256(h))
134 }
135 _ => Err("Invalid hash length".to_string()),
136 }
137 }
138}
139
140impl ObjectHash {
141 pub fn zero_str(kind: HashKind) -> String {
143 match kind {
144 HashKind::Sha1 => "0000000000000000000000000000000000000000".to_string(),
145 HashKind::Sha256 => {
146 "0000000000000000000000000000000000000000000000000000000000000000".to_string()
147 }
148 }
149 }
150
151 pub fn kind(&self) -> HashKind {
153 match self {
154 ObjectHash::Sha1(_) => HashKind::Sha1,
155 ObjectHash::Sha256(_) => HashKind::Sha256,
156 }
157 }
158 pub fn size(&self) -> usize {
160 self.kind().size()
161 }
162
163 pub fn new(data: &[u8]) -> ObjectHash {
165 match get_hash_kind() {
166 HashKind::Sha1 => {
167 let h = sha1::Sha1::digest(data);
168 let mut bytes = [0u8; 20];
169 bytes.copy_from_slice(h.as_ref());
170 ObjectHash::Sha1(bytes)
171 }
172 HashKind::Sha256 => {
173 let h = sha2::Sha256::digest(data);
174 let mut bytes = [0u8; 32];
175 bytes.copy_from_slice(h.as_ref());
176 ObjectHash::Sha256(bytes)
177 }
178 }
179 }
180 pub fn from_type_and_data(object_type: ObjectType, data: &[u8]) -> ObjectHash {
182 let mut d: Vec<u8> = Vec::new();
183 d.extend(object_type.to_data().unwrap());
184 d.push(b' ');
185 d.extend(data.len().to_string().as_bytes());
186 d.push(b'\x00');
187 d.extend(data);
188 ObjectHash::new(&d)
189 }
190 pub fn from_bytes(bytes: &[u8]) -> Result<ObjectHash, String> {
192 let expected_len = get_hash_kind().size();
193 if bytes.len() != expected_len {
194 return Err(format!(
195 "Invalid byte length: got {}, expected {}",
196 bytes.len(),
197 expected_len
198 ));
199 }
200
201 match get_hash_kind() {
202 HashKind::Sha1 => {
203 let mut h = [0u8; 20];
204 h.copy_from_slice(bytes);
205 Ok(ObjectHash::Sha1(h))
206 }
207 HashKind::Sha256 => {
208 let mut h = [0u8; 32];
209 h.copy_from_slice(bytes);
210 Ok(ObjectHash::Sha256(h))
211 }
212 }
213 }
214 pub fn from_stream(data: &mut impl io::Read) -> io::Result<ObjectHash> {
216 match get_hash_kind() {
217 HashKind::Sha1 => {
218 let mut h = [0u8; 20];
219 data.read_exact(&mut h)?;
220 Ok(ObjectHash::Sha1(h))
221 }
222 HashKind::Sha256 => {
223 let mut h = [0u8; 32];
224 data.read_exact(&mut h)?;
225 Ok(ObjectHash::Sha256(h))
226 }
227 }
228 }
229
230 pub fn to_color_str(self) -> String {
232 self.to_string().red().bold().to_string()
233 }
234
235 pub fn to_data(self) -> Vec<u8> {
237 self.as_ref().to_vec()
238 }
239
240 pub fn _to_string(&self) -> String {
242 hex::encode(self.as_ref())
243 }
244
245 pub fn as_mut_bytes(&mut self) -> &mut [u8] {
247 match self {
248 ObjectHash::Sha1(bytes) => bytes.as_mut_slice(),
249 ObjectHash::Sha256(bytes) => bytes.as_mut_slice(),
250 }
251 }
252}
253
254thread_local! {
255 static CURRENT_HASH_KIND: RefCell<HashKind> = RefCell::new(HashKind::default());
259}
260pub fn set_hash_kind(kind: HashKind) {
262 CURRENT_HASH_KIND.with(|h| {
263 *h.borrow_mut() = kind;
264 });
265}
266
267pub fn get_hash_kind() -> HashKind {
269 CURRENT_HASH_KIND.with(|h| *h.borrow())
270}
271pub struct HashKindGuard {
273 prev: HashKind,
274}
275impl Drop for HashKindGuard {
277 fn drop(&mut self) {
278 set_hash_kind(self.prev);
279 }
280}
281pub fn set_hash_kind_for_test(kind: HashKind) -> HashKindGuard {
283 let prev = get_hash_kind();
284 set_hash_kind(kind);
285 HashKindGuard { prev }
286}
287#[cfg(test)]
288mod tests {
289
290 use std::{
291 io::{BufReader, Read, Seek, SeekFrom},
292 str::FromStr,
293 };
294
295 use crate::{
296 hash::{HashKind, ObjectHash, set_hash_kind_for_test},
297 internal::pack::test_pack_download::download_pack_file,
298 };
299
300 #[test]
302 fn test_sha1_new() {
303 let _guard = set_hash_kind_for_test(HashKind::Sha1);
305 let data = "Hello, world!".as_bytes();
307
308 let sha1 = ObjectHash::new(data);
310
311 let expected_sha1_hash = "943a702d06f34599aee1f8da8ef9f7296031d699";
313
314 assert_eq!(sha1.to_string(), expected_sha1_hash);
315 }
316
317 #[test]
319 fn test_sha256_new() {
320 let _guard = set_hash_kind_for_test(HashKind::Sha256);
321 let data = "Hello, world!".as_bytes();
322 let sha256 = ObjectHash::new(data);
323 let expected_sha256_hash =
324 "315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3";
325 assert_eq!(sha256.to_string(), expected_sha256_hash);
326 }
327
328 #[test]
330 fn test_signature_without_delta() {
331 let _guard = set_hash_kind_for_test(HashKind::Sha1);
332 let (source, _dl_guard) = download_pack_file("small-sha1.pack");
333
334 let f = std::fs::File::open(source).unwrap();
335 let mut buffered = BufReader::new(f);
336
337 buffered.seek(SeekFrom::End(-20)).unwrap();
338 let mut buffer = vec![0; 20];
339 buffered.read_exact(&mut buffer).unwrap();
340 let signature = ObjectHash::from_bytes(buffer.as_ref()).unwrap();
341 assert_eq!(signature.kind(), HashKind::Sha1);
342 }
343
344 #[test]
346 fn test_signature_without_delta_sha256() {
347 let _guard = set_hash_kind_for_test(HashKind::Sha256);
348 let (source, _dl_guard) = download_pack_file("small-sha256.pack");
349
350 let f = std::fs::File::open(source).unwrap();
351 let mut buffered = BufReader::new(f);
352
353 buffered.seek(SeekFrom::End(-32)).unwrap();
354 let mut buffer = vec![0; 32];
355 buffered.read_exact(&mut buffer).unwrap();
356 let signature = ObjectHash::from_bytes(buffer.as_ref()).unwrap();
357 assert_eq!(signature.kind(), HashKind::Sha256);
358 }
359
360 #[test]
362 fn test_sha1_from_bytes() {
363 let _guard = set_hash_kind_for_test(HashKind::Sha1);
364 let sha1 = ObjectHash::from_bytes(&[
365 0x8a, 0xb6, 0x86, 0xea, 0xfe, 0xb1, 0xf4, 0x47, 0x02, 0x73, 0x8c, 0x8b, 0x0f, 0x24,
366 0xf2, 0x56, 0x7c, 0x36, 0xda, 0x6d,
367 ])
368 .unwrap();
369
370 assert_eq!(sha1.to_string(), "8ab686eafeb1f44702738c8b0f24f2567c36da6d");
371 }
372
373 #[test]
375 fn test_sha256_from_bytes() {
376 let _guard = set_hash_kind_for_test(HashKind::Sha256);
377 let sha256 = ObjectHash::from_bytes(&[
379 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae,
380 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61,
381 0xf2, 0x00, 0x15, 0xad,
382 ])
383 .unwrap();
384
385 assert_eq!(
386 sha256.to_string(),
387 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
388 );
389 }
390
391 #[test]
393 fn test_from_stream() {
394 let _guard = set_hash_kind_for_test(HashKind::Sha1);
395 let source = [
396 0x8a, 0xb6, 0x86, 0xea, 0xfe, 0xb1, 0xf4, 0x47, 0x02, 0x73, 0x8c, 0x8b, 0x0f, 0x24,
397 0xf2, 0x56, 0x7c, 0x36, 0xda, 0x6d,
398 ];
399 let mut reader = std::io::Cursor::new(source);
400 let sha1 = ObjectHash::from_stream(&mut reader).unwrap();
401 assert_eq!(sha1.to_string(), "8ab686eafeb1f44702738c8b0f24f2567c36da6d");
402 }
403
404 #[test]
406 fn test_sha256_from_stream() {
407 let _guard = set_hash_kind_for_test(HashKind::Sha256);
408 let source = [
409 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae,
410 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61,
411 0xf2, 0x00, 0x15, 0xad,
412 ];
413 let mut reader = std::io::Cursor::new(source);
414 let sha256 = ObjectHash::from_stream(&mut reader).unwrap();
415 assert_eq!(
416 sha256.to_string(),
417 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
418 );
419 }
420
421 #[test]
423 fn test_sha1_from_str() {
424 let _guard = set_hash_kind_for_test(HashKind::Sha1);
425 let hash_str = "8ab686eafeb1f44702738c8b0f24f2567c36da6d";
426
427 match ObjectHash::from_str(hash_str) {
428 Ok(hash) => {
429 assert_eq!(hash.to_string(), "8ab686eafeb1f44702738c8b0f24f2567c36da6d");
430 }
431 Err(e) => println!("Error: {e}"),
432 }
433 }
434
435 #[test]
437 fn test_sha256_from_str() {
438 let _guard = set_hash_kind_for_test(HashKind::Sha256);
439 let hash_str = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad";
440
441 match ObjectHash::from_str(hash_str) {
442 Ok(hash) => {
443 assert_eq!(
444 hash.to_string(),
445 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
446 );
447 }
448 Err(e) => println!("Error: {e}"),
449 }
450 }
451
452 #[test]
454 fn test_sha1_to_string() {
455 let _guard = set_hash_kind_for_test(HashKind::Sha1);
456 let hash_str = "8ab686eafeb1f44702738c8b0f24f2567c36da6d";
457
458 match ObjectHash::from_str(hash_str) {
459 Ok(hash) => {
460 assert_eq!(hash.to_string(), "8ab686eafeb1f44702738c8b0f24f2567c36da6d");
461 }
462 Err(e) => println!("Error: {e}"),
463 }
464 }
465
466 #[test]
468 fn test_sha256_to_string() {
469 let _guard = set_hash_kind_for_test(HashKind::Sha256);
470 let hash_str = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad";
471 match ObjectHash::from_str(hash_str) {
472 Ok(hash) => {
473 assert_eq!(
474 hash.to_string(),
475 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
476 );
477 }
478 Err(e) => println!("Error: {e}"),
479 }
480 }
481
482 #[test]
484 fn test_sha1_to_data() {
485 let _guard = set_hash_kind_for_test(HashKind::Sha1);
486 let hash_str = "8ab686eafeb1f44702738c8b0f24f2567c36da6d";
487
488 match ObjectHash::from_str(hash_str) {
489 Ok(hash) => {
490 assert_eq!(
491 hash.to_data(),
492 vec![
493 0x8a, 0xb6, 0x86, 0xea, 0xfe, 0xb1, 0xf4, 0x47, 0x02, 0x73, 0x8c, 0x8b,
494 0x0f, 0x24, 0xf2, 0x56, 0x7c, 0x36, 0xda, 0x6d
495 ]
496 );
497 }
498 Err(e) => println!("Error: {e}"),
499 }
500 }
501
502 #[test]
504 fn test_sha256_to_data() {
505 let _guard = set_hash_kind_for_test(HashKind::Sha256);
506 let hash_str = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad";
507 match ObjectHash::from_str(hash_str) {
508 Ok(hash) => {
509 assert_eq!(
510 hash.to_data(),
511 vec![
512 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde,
513 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
514 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad,
515 ]
516 );
517 }
518 Err(e) => println!("Error: {e}"),
519 }
520 }
521}