1mod crypt4gh;
2pub mod helpers;
3pub mod pithos;
4pub mod readwrite;
5pub mod streamreadwrite;
6pub mod transformer;
7pub mod transformers;
8
9#[cfg(test)]
10mod tests {
11 use std::io::SeekFrom;
12
13 use crate::helpers::footer_parser::{Footer, FooterParser, FooterParserState};
14 use crate::helpers::notifications::{DirOrFileIdx, Message};
15 use crate::helpers::structs::{EncryptionKey, FileContext, Range};
16 use crate::pithos::structs::FileContextVariants;
17 use crate::readwrite::GenericReadWriter;
18 use crate::streamreadwrite::GenericStreamReadWriter;
19 use crate::transformer::ReadWriter;
20 use crate::transformers::decrypt::ChaCha20Dec;
21 use crate::transformers::decrypt_resilient::ChaChaResilient;
22 use crate::transformers::decrypt_with_parts::ChaCha20DecParts;
23 use crate::transformers::encrypt::{encrypt_chunk, ChaCha20Enc};
24 use crate::transformers::filter::Filter;
25 use crate::transformers::footer::FooterGenerator;
26 use crate::transformers::footer_extractor::FooterExtractor;
27 use crate::transformers::footer_updater::FooterUpdater;
28 use crate::transformers::gzip_comp::GzipEnc;
29 use crate::transformers::hashing_transformer::HashingTransformer;
30 use crate::transformers::pithos_comp_enc::PithosTransformer;
31 use crate::transformers::size_probe::SizeProbe;
32 use crate::transformers::tar::TarEnc;
33 use crate::transformers::zstd_comp::ZstdEnc;
34 use crate::transformers::zstd_decomp::ZstdDec;
35 use base64::prelude::*;
36 use bytes::Bytes;
37 use digest::Digest;
38 use futures::{StreamExt, TryStreamExt};
39 use md5::Md5;
40 use sha2::Sha256;
41 use tempfile::TempDir;
42 use tokio::fs::File;
43 use tokio::io::{AsyncReadExt, AsyncSeekExt};
44
45 #[tokio::test]
46 async fn e2e_compressor_test_with_file() {
47 let temp_dir = TempDir::new().unwrap();
49 let out_path = temp_dir.path().join("test.txt.comp");
50 let out_file = File::create(&out_path).await.unwrap();
51 let in_file = File::open("test.txt").await.unwrap();
52
53 GenericReadWriter::new_with_writer(in_file, out_file)
55 .add_transformer(ZstdEnc::new())
56 .add_transformer(ZstdDec::new())
57 .process()
58 .await
59 .unwrap();
60
61 let mut original_file = File::open("test.txt").await.unwrap();
63 let mut original_bytes = String::new();
64 original_file
65 .read_to_string(&mut original_bytes)
66 .await
67 .unwrap();
68
69 let mut also_original_file = File::open(out_path).await.unwrap();
70 let mut also_original_bytes = String::new();
71 also_original_file
72 .read_to_string(&mut also_original_bytes)
73 .await
74 .unwrap();
75
76 assert_eq!(original_bytes, also_original_bytes)
77 }
78
79 #[tokio::test]
80 async fn e2e_encrypt_test_with_vec_no_pad() {
81 let input = b"This is a very very important test".to_vec();
82 let mut output = Vec::new();
83
84 GenericReadWriter::new_with_writer(input.as_ref(), &mut output)
86 .add_transformer(
87 ChaCha20Enc::new_with_fixed(
88 b"99wj3485nxgyq5ub9zd3e7jsrq7a92ea"
89 .to_vec()
90 .to_vec()
91 .try_into()
92 .unwrap(),
93 )
94 .unwrap(),
95 )
96 .add_transformer(
97 ChaCha20Dec::new_with_fixed(
98 b"99wj3485nxgyq5ub9zd3e7jsrq7a92ea"
99 .to_vec()
100 .to_vec()
101 .try_into()
102 .unwrap(),
103 )
104 .unwrap(),
105 )
106 .process()
107 .await
108 .unwrap();
109
110 assert_eq!(input, output);
111 }
112
113 #[tokio::test]
114 async fn e2e_encrypt_test_with_file_no_pad() {
115 let temp_dir = TempDir::new().unwrap();
117 let out_path = temp_dir.path().join("test.txt.out");
118 let file_out = File::create(&out_path).await.unwrap();
119 let file_in = File::open("test.txt").await.unwrap();
120
121 GenericReadWriter::new_with_writer(file_in, file_out)
123 .add_transformer(
124 ChaCha20Enc::new_with_fixed(
125 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
126 .to_vec()
127 .to_vec()
128 .try_into()
129 .unwrap(),
130 )
131 .unwrap(),
132 )
133 .add_transformer(
134 ChaCha20Dec::new_with_fixed(
135 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
136 .to_vec()
137 .to_vec()
138 .try_into()
139 .unwrap(),
140 )
141 .unwrap(),
142 )
143 .process()
144 .await
145 .unwrap();
146
147 let mut original_file = File::open("test.txt").await.unwrap();
148 let mut also_original_file = File::open(out_path).await.unwrap();
149 let mut buf1 = String::new();
150 let mut buf2 = String::new();
151 original_file.read_to_string(&mut buf1).await.unwrap();
152 also_original_file.read_to_string(&mut buf2).await.unwrap();
153
154 assert_eq!(buf1, buf2)
155 }
156
157 #[tokio::test]
158 async fn e2e_test_roundtrip_with_file() {
159 let temp_dir = TempDir::new().unwrap();
161 let out_path = temp_dir.path().join("test.txt.out");
162 let file_out = File::create(&out_path).await.unwrap();
163 let file_in = File::open("test.txt").await.unwrap();
164
165 GenericReadWriter::new_with_writer(file_in, file_out)
167 .add_transformer(ZstdEnc::new())
168 .add_transformer(ZstdEnc::new())
169 .add_transformer(
170 ChaCha20Enc::new_with_fixed(
171 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
172 .to_vec()
173 .to_vec()
174 .try_into()
175 .unwrap(),
176 )
177 .unwrap(),
178 )
179 .add_transformer(
180 ChaCha20Enc::new_with_fixed(
181 b"99wj3485nxgyq5ub9zd3e7jsrq7a92ea"
182 .to_vec()
183 .to_vec()
184 .try_into()
185 .unwrap(),
186 )
187 .unwrap(),
188 )
189 .add_transformer(
190 ChaCha20Dec::new_with_fixed(
191 b"99wj3485nxgyq5ub9zd3e7jsrq7a92ea"
192 .to_vec()
193 .to_vec()
194 .try_into()
195 .unwrap(),
196 )
197 .unwrap(),
198 )
199 .add_transformer(
200 ChaCha20Dec::new_with_fixed(
201 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
202 .to_vec()
203 .to_vec()
204 .try_into()
205 .unwrap(),
206 )
207 .unwrap(),
208 )
209 .add_transformer(ZstdDec::new())
210 .add_transformer(ZstdDec::new())
211 .process()
212 .await
213 .unwrap();
214
215 let mut file = File::open("test.txt").await.unwrap();
216 let mut file2 = File::open(out_path).await.unwrap();
217 let mut buf1 = String::new();
218 let mut buf2 = String::new();
219 file.read_to_string(&mut buf1).await.unwrap();
220 file2.read_to_string(&mut buf2).await.unwrap();
221
222 assert_eq!(buf1, buf2)
223 }
224
225 #[tokio::test]
226 async fn test_with_vec() {
227 let input = b"This is a very very important test".to_vec();
228 let mut output = Vec::new();
229
230 GenericReadWriter::new_with_writer(input.as_ref(), &mut output)
232 .add_transformer(ZstdEnc::new())
233 .add_transformer(ZstdEnc::new()) .add_transformer(
235 ChaCha20Enc::new_with_fixed(
236 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
237 .to_vec()
238 .to_vec()
239 .try_into()
240 .unwrap(),
241 )
242 .unwrap(),
243 )
244 .add_transformer(
245 ChaCha20Enc::new_with_fixed(
246 b"99wj3485nxgyq5ub9zd3e7jsrq7a92ea"
247 .to_vec()
248 .to_vec()
249 .try_into()
250 .unwrap(),
251 )
252 .unwrap(),
253 )
254 .add_transformer(
255 ChaCha20Dec::new_with_fixed(
256 b"99wj3485nxgyq5ub9zd3e7jsrq7a92ea"
257 .to_vec()
258 .to_vec()
259 .try_into()
260 .unwrap(),
261 )
262 .unwrap(),
263 )
264 .add_transformer(
265 ChaCha20Dec::new_with_fixed(
266 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
267 .to_vec()
268 .to_vec()
269 .try_into()
270 .unwrap(),
271 )
272 .unwrap(),
273 )
274 .add_transformer(ZstdDec::new())
275 .add_transformer(ZstdDec::new()) .process()
277 .await
278 .unwrap();
279
280 assert_eq!(input, output)
281 }
282
283 #[tokio::test]
284 async fn test_footer_parsing() {
285 let temp_dir = TempDir::new().unwrap();
287 let out_path = temp_dir.path().join("test.txt.out");
288 let file_out = File::create(&out_path).await.unwrap();
289 let file_in = File::open("test.txt").await.unwrap();
290
291 GenericReadWriter::new_with_writer(file_in, file_out)
292 .add_transformer(ZstdEnc::new())
293 .add_transformer(
294 FooterGenerator::new_with_ctx(FileContext {
295 file_path: "test.txt".to_string(),
296 ..Default::default()
297 })
298 .unwrap(),
299 )
300 .process()
301 .await
302 .unwrap();
303
304 let mut footer_file = File::open(out_path).await.unwrap();
305 footer_file.seek(SeekFrom::End(-65536 * 2)).await.unwrap();
306
307 let buf: &mut [u8; 65536 * 2] = &mut [0; 65536 * 2];
308 footer_file.read_exact(buf).await.unwrap();
309
310 let mut fp = FooterParser::new(buf).unwrap();
311 fp = fp.parse().unwrap();
312
313 assert!(matches!(fp.state, FooterParserState::Decoded))
314 }
315
316 #[tokio::test]
317 async fn test_footer_parsing_encrypted() {
318 let temp_dir = TempDir::new().unwrap();
320 let out_path = temp_dir.path().join("test.txt.out");
321 let file_out = File::create(&out_path).await.unwrap();
322 let file_in = File::open("test.txt").await.unwrap();
323
324 GenericReadWriter::new_with_writer(file_in, file_out)
326 .add_transformer(ZstdEnc::new())
327 .add_transformer(
328 ChaCha20Enc::new_with_fixed(
329 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
330 .to_vec()
331 .try_into()
332 .unwrap(),
333 )
334 .unwrap(),
335 )
336 .add_transformer(
337 FooterGenerator::new_with_ctx(FileContext {
338 file_path: "test.txt".to_string(),
339 encryption_key: EncryptionKey::Same(
340 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
341 .to_vec()
342 .try_into()
343 .unwrap(),
344 ),
345 ..Default::default()
346 })
347 .unwrap(),
348 )
349 .process()
350 .await
351 .unwrap();
352
353 let mut footer_file = File::open(out_path).await.unwrap();
354 footer_file
355 .seek(SeekFrom::End((-65536 - 28) * 2))
356 .await
357 .unwrap();
358
359 let buf: &mut [u8; (65536 + 28) * 2] = &mut [0; (65536 + 28) * 2];
360 footer_file.read_exact(buf).await.unwrap();
361
362 let mut fp = FooterParser::new(buf).unwrap();
363 fp = fp.add_recipient(b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea");
364 fp = fp.parse().unwrap();
365 assert!(matches!(fp.state, FooterParserState::Decoded));
366
367 let _: Footer = fp.try_into().unwrap();
368 }
369
370 #[tokio::test]
371 async fn test_simple_filter_range() {
372 let input1 = b"This is a very very important test".to_vec();
374 let mut output_01 = Vec::new();
375 GenericReadWriter::new_with_writer(input1.as_ref(), &mut output_01)
376 .add_transformer(Filter::new_with_range(Range { from: 0, to: 3 }))
377 .process()
378 .await
379 .unwrap();
380 assert_eq!(output_01, b"Thi".to_vec());
381
382 let input2 = b"This is a very very important test".to_vec();
384 let mut output_02 = Vec::new();
385 GenericReadWriter::new_with_writer(input2.as_ref(), &mut output_02)
386 .add_transformer(Filter::new_with_range(Range { from: 6, to: 16 }))
387 .process()
388 .await
389 .unwrap();
390 assert_eq!(output_02, b"s a very v".to_vec());
391
392 let input3 = b"This is a very very important test".to_vec();
394 let mut output_03 = Vec::new();
395 GenericReadWriter::new_with_writer(input3.as_ref(), &mut output_03)
396 .add_transformer(Filter::new_with_range(Range {
397 from: 25,
398 to: input3.len() as u64,
399 }))
400 .process()
401 .await
402 .unwrap();
403 assert_eq!(output_03, b"tant test".to_vec());
404 }
405
406 #[tokio::test]
407 async fn test_complex_filter() {
408 let input = b"This is a very very important test".to_vec();
409 let mut output = Vec::new();
410
411 GenericReadWriter::new_with_writer(input.as_ref(), &mut output)
413 .add_transformer(ZstdEnc::new())
414 .add_transformer(ZstdEnc::new()) .add_transformer(
416 ChaCha20Enc::new_with_fixed(
417 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
418 .to_vec()
419 .to_vec()
420 .try_into()
421 .unwrap(),
422 )
423 .unwrap(),
424 )
425 .add_transformer(
426 ChaCha20Enc::new_with_fixed(
427 b"99wj3485nxgyq5ub9zd3e7jsrq7a92ea"
428 .to_vec()
429 .to_vec()
430 .try_into()
431 .unwrap(),
432 )
433 .unwrap(),
434 )
435 .add_transformer(
436 ChaCha20Dec::new_with_fixed(
437 b"99wj3485nxgyq5ub9zd3e7jsrq7a92ea"
438 .to_vec()
439 .to_vec()
440 .try_into()
441 .unwrap(),
442 )
443 .unwrap(),
444 )
445 .add_transformer(
446 ChaCha20Dec::new_with_fixed(
447 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
448 .to_vec()
449 .to_vec()
450 .try_into()
451 .unwrap(),
452 )
453 .unwrap(),
454 )
455 .add_transformer(ZstdDec::new())
456 .add_transformer(ZstdDec::new())
457 .add_transformer(Filter::new_with_range(Range { from: 0, to: 3 }))
458 .process()
459 .await
460 .unwrap();
461
462 assert_eq!(output, b"Thi".to_vec());
463 }
464
465 #[tokio::test]
466 async fn test_read_write_multifile() {
467 let file1 = b"Lorem ipsum dolor sit amet, consetetur sadipscing elitr.".to_vec();
468 let file2 = b"Stet clita kasd gubergren, no sea takimata sanctus.".to_vec();
469 let mut output: Vec<u8> = Vec::new();
470
471 let combined = Vec::from_iter(file1.clone().into_iter().chain(file2.clone()));
472
473 let (sx, rx) = async_channel::bounded(10);
474 sx.send(Message::FileContext(FileContext {
475 file_path: "file1.txt".to_string(),
476 compressed_size: file1.len() as u64,
477 decompressed_size: file1.len() as u64,
478 compression: true,
479 ..Default::default()
480 }))
481 .await
482 .unwrap();
483
484 sx.send(Message::FileContext(FileContext {
485 file_path: "file2.txt".to_string(),
486 compressed_size: file2.len() as u64,
487 decompressed_size: file2.len() as u64,
488 compression: false,
489 ..Default::default()
490 }))
491 .await
492 .unwrap();
493
494 let mut aswr = GenericReadWriter::new_with_writer(combined.as_ref(), &mut output);
496 aswr.add_message_receiver(rx).await.unwrap();
497 aswr = aswr
498 .add_transformer(ZstdEnc::new())
499 .add_transformer(
500 ChaCha20Enc::new_with_fixed(
501 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
502 .to_vec()
503 .to_vec()
504 .try_into()
505 .unwrap(),
506 )
507 .unwrap(),
508 )
509 .add_transformer(
510 ChaCha20Dec::new_with_fixed(
511 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
512 .to_vec()
513 .to_vec()
514 .try_into()
515 .unwrap(),
516 )
517 .unwrap(),
518 )
519 .add_transformer(ZstdDec::new());
520 aswr.process().await.unwrap();
521 drop(aswr);
522
523 assert_eq!(output, combined);
524 }
525
526 #[tokio::test]
527 async fn stream_test() {
528 use futures::stream;
529
530 let bytes_stream = stream::iter(vec![
531 Ok(Bytes::from(
532 b"One morning, when Gregor Samsa woke from troubled dreams, ".to_vec(),
533 )),
534 Ok(Bytes::from(
535 b"he found himself transformed in his bed into a horrible vermin.".to_vec(),
536 )),
537 ]);
538
539 let mut output = Vec::new();
541 GenericStreamReadWriter::new_with_writer(bytes_stream, &mut output)
542 .add_transformer(ZstdEnc::new())
543 .add_transformer(
544 ChaCha20Enc::new_with_fixed(
545 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
546 .to_vec()
547 .to_vec()
548 .try_into()
549 .unwrap(),
550 )
551 .unwrap(),
552 )
553 .add_transformer(
554 ChaCha20Dec::new_with_fixed(
555 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
556 .to_vec()
557 .to_vec()
558 .try_into()
559 .unwrap(),
560 )
561 .unwrap(),
562 )
563 .add_transformer(ZstdDec::new())
564 .process()
565 .await
566 .unwrap();
567
568 assert_eq!(
569 output,
570 b"One morning, when Gregor Samsa woke from troubled dreams, he found himself transformed in his bed into a horrible vermin.".to_vec()
571 );
572 }
573
574 #[tokio::test]
575 async fn e2e_test_read_write_multifile_tar_small() {
576 let temp_dir = TempDir::new().unwrap();
578 let out_path = temp_dir.path().join("test.txt.out");
579 let mut file_out = File::create(&out_path).await.unwrap();
580
581 let file1 = b"The quick, brown fox jumps over a lazy dog.".to_vec();
582 let file2 =
583 b"Junk MTV quiz graced by fox whelps. Bawds jog, flick quartz, vex nymphs.".to_vec();
584 let combined = Vec::from_iter(file1.clone().into_iter().chain(file2.clone()));
585
586 let (sx, rx) = async_channel::bounded(10);
588 sx.send(Message::FileContext(FileContext {
589 file_path: "file1.txt".to_string(),
590 compressed_size: file1.len() as u64,
591 decompressed_size: file1.len() as u64,
592 compression: true,
593 encryption_key: EncryptionKey::Same(
594 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
595 .to_vec()
596 .to_vec()
597 .try_into()
598 .unwrap(),
599 ),
600 ..Default::default()
601 }))
602 .await
603 .unwrap();
604
605 sx.send(Message::FileContext(FileContext {
606 file_path: "file2.txt".to_string(),
607 compressed_size: file2.len() as u64,
608 decompressed_size: file2.len() as u64,
609 compression: false,
610 encryption_key: EncryptionKey::Same(
611 b"xxwj3485nxgyq5ub9zd3e7jsrq7a92ea"
612 .to_vec()
613 .to_vec()
614 .try_into()
615 .unwrap(),
616 ),
617 ..Default::default()
618 }))
619 .await
620 .unwrap();
621
622 let mut aswr = GenericReadWriter::new_with_writer(combined.as_ref(), &mut file_out)
624 .add_transformer(TarEnc::new());
625 aswr.add_message_receiver(rx).await.unwrap();
626 aswr.process().await.unwrap();
627 }
628
629 #[tokio::test]
630 async fn e2e_test_read_write_multifile_tar_real() {
631 let temp_dir = TempDir::new().unwrap();
633 let out_path = temp_dir.path().join("test.txt.out");
634 let mut file_out = File::create(&out_path).await.unwrap();
635
636 let mut file1 = File::open("test.txt").await.unwrap();
637 let mut file2 = File::open("test.txt").await.unwrap();
638 let mut combined = Vec::new();
639 file1.read_to_end(&mut combined).await.unwrap();
640 file2.read_to_end(&mut combined).await.unwrap();
641
642 let (sx, rx) = async_channel::bounded(10);
644 sx.send(Message::FileContext(FileContext {
645 file_path: "file1.txt".to_string(),
646 compressed_size: file1.metadata().await.unwrap().len(),
647 decompressed_size: file1.metadata().await.unwrap().len(),
648 compression: true,
649 encryption_key: EncryptionKey::Same(
650 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
651 .to_vec()
652 .to_vec()
653 .try_into()
654 .unwrap(),
655 ),
656 ..Default::default()
657 }))
658 .await
659 .unwrap();
660
661 sx.send(Message::FileContext(FileContext {
662 file_path: "file2.txt".to_string(),
663 compressed_size: file2.metadata().await.unwrap().len(),
664 decompressed_size: file2.metadata().await.unwrap().len(),
665 compression: false,
666 encryption_key: EncryptionKey::Same(
667 b"xxwj3485nxgyq5ub9zd3e7jsrq7a92ea"
668 .to_vec()
669 .to_vec()
670 .try_into()
671 .unwrap(),
672 ),
673 ..Default::default()
674 }))
675 .await
676 .unwrap();
677
678 let mut aswr = GenericReadWriter::new_with_writer(combined.as_ref(), &mut file_out)
680 .add_transformer(TarEnc::new());
681 aswr.add_message_receiver(rx).await.unwrap();
682 aswr.process().await.unwrap();
683 }
684
685 #[tokio::test]
686 async fn e2e_test_stream_write_multifile_tar_real() {
687 let temp_dir = TempDir::new().unwrap();
689 let out_path = temp_dir.path().join("test.txt.out");
690 let mut file_out = File::create(&out_path).await.unwrap();
691
692 let file1 = File::open("test.txt").await.unwrap();
693 let file2 = File::open("test.txt").await.unwrap();
694 let file1_size = file1.metadata().await.unwrap().len();
695 let file2_size = file2.metadata().await.unwrap().len();
696 let stream1 = tokio_util::io::ReaderStream::new(file1);
697 let stream2 = tokio_util::io::ReaderStream::new(file2);
698 let chained = stream1.chain(stream2);
699 let mapped = chained
700 .map_err(|_| Box::<dyn std::error::Error + Send + Sync + 'static>::from("a_str_error"));
701
702 let (sx, rx) = async_channel::bounded(10);
704 sx.send(Message::FileContext(FileContext {
705 file_path: "file1.txt".to_string(),
706 compressed_size: file1_size,
707 decompressed_size: file1_size,
708 ..Default::default()
709 }))
710 .await
711 .unwrap();
712
713 sx.send(Message::FileContext(FileContext {
714 file_path: "file2.txt".to_string(),
715 compressed_size: file2_size,
716 decompressed_size: file2_size,
717 ..Default::default()
718 }))
719 .await
720 .unwrap();
721
722 let mut aswr = GenericStreamReadWriter::new_with_writer(mapped, &mut file_out)
724 .add_transformer(TarEnc::new());
725 aswr.add_message_receiver(rx).await.unwrap();
726 aswr.process().await.unwrap();
727 }
728
729 #[tokio::test]
730 async fn e2e_test_stream_tar_gz() {
731 let temp_dir = TempDir::new().unwrap();
733 let out_path = temp_dir.path().join("test.txt.out");
734 let mut file_out = File::create(&out_path).await.unwrap();
735
736 let file1 = File::open("test.txt").await.unwrap();
737 let file2 = File::open("test.txt").await.unwrap();
738 let file1_size = file1.metadata().await.unwrap().len();
739 let file2_size = file2.metadata().await.unwrap().len();
740 let stream1 = tokio_util::io::ReaderStream::new(file1);
741 let stream2 = tokio_util::io::ReaderStream::new(file2);
742 let chained = stream1.chain(stream2);
743 let mapped = chained
744 .map_err(|_| Box::<dyn std::error::Error + Send + Sync + 'static>::from("a_str_error"));
745
746 let (sx, rx) = async_channel::bounded(10);
747 sx.send(Message::FileContext(FileContext {
748 file_path: "file1.txt".to_string(),
749 compressed_size: file1_size,
750 decompressed_size: file1_size,
751 ..Default::default()
752 }))
753 .await
754 .unwrap();
755
756 sx.send(Message::FileContext(FileContext {
757 file_path: "file2.txt".to_string(),
758 compressed_size: file2_size,
759 decompressed_size: file2_size,
760 ..Default::default()
761 }))
762 .await
763 .unwrap();
764
765 let mut aswr = GenericStreamReadWriter::new_with_writer(mapped, &mut file_out)
767 .add_transformer(TarEnc::new())
768 .add_transformer(GzipEnc::new());
769 aswr.add_message_receiver(rx).await.unwrap();
770 aswr.process().await.unwrap();
771 }
772
773 #[tokio::test]
774 async fn hashing_transformer_test() {
775 let input = b"Lorem ipsum dolor sit amet, consectetuer adipiscing elit.".to_vec();
776 let mut output = Vec::new();
777
778 let (size_probe, rx) = SizeProbe::new();
779 let (md5_transformer, md5_rcv) =
780 HashingTransformer::new_with_backchannel(Md5::new(), "md5".to_string());
781 let (sha256_transformer, sha256_rcv) =
782 HashingTransformer::new_with_backchannel(Sha256::new(), "sha256".to_string());
783
784 GenericReadWriter::new_with_writer(input.as_ref(), &mut output)
786 .add_transformer(size_probe)
787 .add_transformer(md5_transformer)
788 .add_transformer(sha256_transformer)
789 .process()
790 .await
791 .unwrap();
792
793 let size = rx.try_recv().unwrap();
794 assert_eq!(size, 57);
795
796 let md5 = md5_rcv.try_recv().unwrap();
797 assert_eq!(md5, "a84e9dae73341f1e9764f349701a5adf".to_string());
798
799 let sha256 = sha256_rcv.try_recv().unwrap();
800 assert_eq!(
801 sha256,
802 "1d32dc481e105799b079b5a1b18c2e302bc43bc5feac01450c7ffa50a1c65b92".to_string()
803 );
804 }
805
806 #[tokio::test]
807 async fn e2e_test_stream_tar_folder() {
808 let temp_dir = TempDir::new().unwrap();
810 let out_path = temp_dir.path().join("test.txt.out");
811 let mut file_out = File::create(&out_path).await.unwrap();
812
813 let file1 = File::open("test.txt").await.unwrap();
814 let file2 = File::open("test.txt").await.unwrap();
815 let file1_size = file1.metadata().await.unwrap().len();
816 let file2_size = file2.metadata().await.unwrap().len();
817 let stream1 = tokio_util::io::ReaderStream::new(file1);
818 let stream2 = tokio_util::io::ReaderStream::new(file2);
819 let chained = stream1.chain(stream2);
820 let mapped = chained
821 .map_err(|_| Box::<dyn std::error::Error + Send + Sync + 'static>::from("a_str_error"));
822
823 let (sx, rx) = async_channel::bounded(10);
825 sx.send(Message::FileContext(FileContext {
826 file_path: "blup/".to_string(),
827 compressed_size: 0,
828 decompressed_size: 0,
829 is_dir: true,
830 ..Default::default()
831 }))
832 .await
833 .unwrap();
834
835 sx.send(Message::FileContext(FileContext {
836 file_path: "blup/file1.txt".to_string(),
837 compressed_size: file1_size,
838 decompressed_size: file1_size,
839 ..Default::default()
840 }))
841 .await
842 .unwrap();
843
844 sx.send(Message::FileContext(FileContext {
845 file_path: "blip/".to_string(),
846 compressed_size: 0,
847 decompressed_size: 0,
848 is_dir: true,
849 ..Default::default()
850 }))
851 .await
852 .unwrap();
853
854 sx.send(Message::FileContext(FileContext {
855 file_path: "blip/file2.txt".to_string(),
856 compressed_size: file2_size,
857 decompressed_size: file2_size,
858 ..Default::default()
859 }))
860 .await
861 .unwrap();
862
863 let mut aswr = GenericStreamReadWriter::new_with_writer(mapped, &mut file_out)
865 .add_transformer(TarEnc::new());
866 aswr.add_message_receiver(rx).await.unwrap();
867 aswr.process().await.unwrap();
868 }
869
870 #[tokio::test]
871 async fn e2e_pithos_tar_gz() {
872 let temp_dir = TempDir::new().unwrap();
874 let pithos_out_path = temp_dir.path().join("test.txt.out.pto");
875 let tar_gz_out_path = temp_dir.path().join("test.txt.out.tar.gz");
876 let mut pithos_out = File::create(&pithos_out_path).await.unwrap();
877
878 let file1 = File::open("test.txt").await.unwrap();
879 let file2 = File::open("test.txt").await.unwrap();
880 let file1_size = file1.metadata().await.unwrap().len();
881 let file2_size = file2.metadata().await.unwrap().len();
882 let stream1 = tokio_util::io::ReaderStream::new(file1);
883 let stream2 = tokio_util::io::ReaderStream::new(file2);
884 let chained = stream1.chain(stream2);
885 let mapped = chained
886 .map_err(|_| Box::<dyn std::error::Error + Send + Sync + 'static>::from("a_str_error"));
887
888 let (sx, rx) = async_channel::bounded(10);
890 let privkey_bytes = BASE64_STANDARD
891 .decode("MC4CAQAwBQYDK2VuBCIEIFDnbf0aEpZxwEdy1qG4xpV8gVNq7zEREtMjLzCE6R5x")
892 .unwrap();
893 let privkey: [u8; 32] = privkey_bytes[privkey_bytes.len() - 32..]
894 .to_vec()
895 .try_into()
896 .unwrap();
897
898 let pubkey_bytes = BASE64_STANDARD
899 .decode("MCowBQYDK2VuAyEA2laqNukb4+2am7QdC6eDANu1DDuKdC5LPtYQM+XE5k8=")
900 .unwrap();
901 let pubkey: [u8; 32] = pubkey_bytes[pubkey_bytes.len() - 32..]
902 .to_vec()
903 .try_into()
904 .unwrap();
905
906 sx.send(Message::FileContext(FileContext {
907 file_path: "file1.txt".to_string(),
908 compressed_size: file1_size,
909 decompressed_size: file1_size,
910 recipients_pubkeys: vec![pubkey],
911 encryption_key: EncryptionKey::Same(
912 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
913 .to_vec()
914 .to_vec()
915 .try_into()
916 .unwrap(),
917 ),
918 ..Default::default()
919 }))
920 .await
921 .unwrap();
922
923 sx.send(Message::FileContext(FileContext {
924 file_path: "file2.txt".to_string(),
925 compressed_size: file2_size,
926 decompressed_size: file2_size,
927 recipients_pubkeys: vec![pubkey],
928 encryption_key: EncryptionKey::Same(
929 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
930 .to_vec()
931 .to_vec()
932 .try_into()
933 .unwrap(),
934 ),
935 ..Default::default()
936 }))
937 .await
938 .unwrap();
939
940 let mut aswr = GenericStreamReadWriter::new_with_writer(mapped, &mut pithos_out)
942 .add_transformer(PithosTransformer::new())
943 .add_transformer(FooterGenerator::new(None));
944 aswr.add_message_receiver(rx).await.unwrap();
945 aswr.process().await.unwrap();
946
947 let mut pithos_in = File::open(&pithos_out_path).await.unwrap();
949 let file_meta = pithos_in.metadata().await.unwrap();
950 let footer_prediction = if file_meta.len() < 65536 * 2 {
951 file_meta.len() } else {
953 65536 * 2
954 };
955
956 pithos_in
958 .seek(SeekFrom::End(-(footer_prediction as i64)))
959 .await
960 .unwrap();
961 let buf = &mut vec![0; footer_prediction as usize];
962 pithos_in.read_exact(buf).await.unwrap();
963
964 let mut parser = FooterParser::new(buf).unwrap();
965 parser = parser.add_recipient(&privkey);
966 parser = parser.parse().unwrap();
967
968 let mut missing_buf;
970 if let FooterParserState::Missing(missing_bytes) = parser.state {
971 let needed_bytes = footer_prediction + missing_bytes as u64;
972 pithos_in
973 .seek(SeekFrom::End(-(needed_bytes as i64)))
974 .await
975 .unwrap();
976 missing_buf = vec![0; missing_bytes];
977 pithos_in.read_exact(&mut missing_buf).await.unwrap();
978
979 parser = parser.add_bytes(&missing_buf).unwrap();
980 parser = parser.parse().unwrap()
981 }
982
983 let footer: Footer = parser.try_into().unwrap();
985
986 let keys = footer
987 .encryption_keys
988 .map(|keys| {
989 keys.keys
990 .iter()
991 .filter_map(|(k, idx)| {
992 if let DirOrFileIdx::File(i) = idx {
993 Some((k.clone(), *i))
994 } else {
995 None
996 }
997 })
998 .collect::<Vec<_>>()
999 })
1000 .unwrap_or_default();
1001
1002 let mut tar_gz_file = File::create(&tar_gz_out_path).await.unwrap();
1003 let read_stream = tokio_util::io::ReaderStream::new(pithos_in)
1004 .map_err(|_| Box::<dyn std::error::Error + Send + Sync + 'static>::from("a_str_error"));
1005
1006 let (sx2, rx2) = async_channel::bounded(10);
1007 let mut reader = GenericStreamReadWriter::new_with_writer(read_stream, &mut tar_gz_file)
1008 .add_transformer(ChaCha20Dec::new_with_fixed_list(keys).unwrap())
1009 .add_transformer(ZstdDec::new())
1010 .add_transformer(TarEnc::new())
1011 .add_transformer(GzipEnc::new());
1012 reader.add_message_receiver(rx2).await.unwrap();
1013
1014 for (idx, file) in footer.table_of_contents.files.into_iter().enumerate() {
1015 if let FileContextVariants::FileDecrypted(file) = file {
1016 sx2.send(Message::FileContext(
1017 file.try_into_file_context(idx).unwrap(),
1018 ))
1019 .await
1020 .unwrap();
1021 }
1022 }
1023 reader.process().await.unwrap();
1024 }
1025
1026 #[tokio::test]
1027 async fn e2e_pithos_rewrite_footer() {
1028 let temp_dir = TempDir::new().unwrap();
1030 let pithos_out_path1 = temp_dir.path().join("test.txt.out.pto");
1031 let pithos_out_path2 = temp_dir.path().join("test.txt.out.upd.pto");
1032 let mut pithos_out = File::create(&pithos_out_path1).await.unwrap();
1033
1034 let input_file = File::open("test.txt").await.unwrap();
1035 let input_size = input_file.metadata().await.unwrap().len();
1036 let input_stream = tokio_util::io::ReaderStream::new(input_file)
1037 .map_err(|_| Box::<dyn std::error::Error + Send + Sync + 'static>::from("a_str_error"));
1038
1039 let privkey_bytes = BASE64_STANDARD
1041 .decode("MC4CAQAwBQYDK2VuBCIEIFDnbf0aEpZxwEdy1qG4xpV8gVNq7zEREtMjLzCE6R5x")
1042 .unwrap();
1043 let privkey: [u8; 32] = privkey_bytes[privkey_bytes.len() - 32..]
1044 .to_vec()
1045 .try_into()
1046 .unwrap();
1047
1048 let pubkey_bytes = BASE64_STANDARD
1049 .decode("MCowBQYDK2VuAyEA2laqNukb4+2am7QdC6eDANu1DDuKdC5LPtYQM+XE5k8=")
1050 .unwrap();
1051 let pubkey: [u8; 32] = pubkey_bytes[pubkey_bytes.len() - 32..]
1052 .to_vec()
1053 .try_into()
1054 .unwrap();
1055
1056 let (sx, rx) = async_channel::bounded(10);
1057 sx.send(Message::FileContext(FileContext {
1058 file_path: "file1.txt".to_string(),
1059 compressed_size: input_size,
1060 decompressed_size: input_size,
1061 recipients_pubkeys: vec![pubkey],
1062 encryption_key: EncryptionKey::Same(
1063 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
1064 .to_vec()
1065 .to_vec()
1066 .try_into()
1067 .unwrap(),
1068 ),
1069 ..Default::default()
1070 }))
1071 .await
1072 .unwrap();
1073
1074 let mut aswr = GenericStreamReadWriter::new_with_writer(input_stream, &mut pithos_out)
1076 .add_transformer(PithosTransformer::new())
1077 .add_transformer(FooterGenerator::new(None));
1078 aswr.add_message_receiver(rx).await.unwrap();
1079 aswr.process().await.unwrap();
1080
1081 let mut pithos_input = File::open(&pithos_out_path1).await.unwrap();
1083 let file_meta = pithos_input.metadata().await.unwrap();
1084
1085 let footer_prediction = if file_meta.len() < 65536 * 2 {
1086 file_meta.len() } else {
1088 65536 * 2
1089 };
1090
1091 pithos_input
1093 .seek(SeekFrom::End(-(footer_prediction as i64)))
1094 .await
1095 .unwrap();
1096 let buf = &mut vec![0; footer_prediction as usize];
1097 pithos_input.read_exact(buf).await.unwrap();
1098
1099 let mut parser = FooterParser::new(buf).unwrap();
1100 parser = parser.add_recipient(&privkey);
1101 parser = parser.parse().unwrap();
1102
1103 let mut missing_buf;
1105 if let FooterParserState::Missing(missing_bytes) = parser.state {
1106 let needed_bytes = footer_prediction + missing_bytes as u64;
1107 pithos_input
1108 .seek(SeekFrom::End(-(needed_bytes as i64)))
1109 .await
1110 .unwrap();
1111 missing_buf = vec![0; missing_bytes];
1112 pithos_input.read_exact(&mut missing_buf).await.unwrap();
1113
1114 parser = parser.add_bytes(&missing_buf).unwrap();
1115 parser = parser.parse().unwrap()
1116 }
1117
1118 let footer: Footer = parser.try_into().unwrap();
1120
1121 pithos_input.seek(SeekFrom::Start(0)).await.unwrap();
1123 let read_stream = tokio_util::io::ReaderStream::new(pithos_input)
1124 .map_err(|_| Box::<dyn std::error::Error + Send + Sync + 'static>::from("a_str_error"));
1125
1126 let privkey_bytes_2 = BASE64_STANDARD
1127 .decode("MC4CAQAwBQYDK2VuBCIEIMhHHRAu72qdkx9I4D08RD3OQniJxGUI420aPlZwAJtX")
1128 .unwrap();
1129 let privkey_2: [u8; 32] = privkey_bytes_2[privkey_bytes_2.len() - 32..]
1130 .to_vec()
1131 .try_into()
1132 .unwrap();
1133
1134 let pubkey_bytes_2 = BASE64_STANDARD
1135 .decode("MCowBQYDK2VuAyEAoqu7pzwam2uks5EseS06jQP6ISX42f613KKWm8cLM1M=")
1136 .unwrap();
1137 let pubkey_2: [u8; 32] = pubkey_bytes_2[pubkey_bytes_2.len() - 32..]
1138 .to_vec()
1139 .try_into()
1140 .unwrap();
1141
1142 let (_, rx2) = async_channel::bounded(10);
1143 let mut pithos_out_2 = File::create(&pithos_out_path2).await.unwrap();
1144 let mut reader = GenericStreamReadWriter::new_with_writer(read_stream, &mut pithos_out_2)
1145 .add_transformer(FooterUpdater::new(vec![pubkey_2], footer));
1146 reader.add_message_receiver(rx2).await.unwrap();
1147 reader.process().await.unwrap();
1148
1149 let mut pithos_input = File::open(pithos_out_path2).await.unwrap();
1151 let file_meta = pithos_input.metadata().await.unwrap();
1152
1153 let footer_prediction = if file_meta.len() < 65536 * 2 {
1154 file_meta.len() } else {
1156 65536 * 2
1157 };
1158
1159 pithos_input
1161 .seek(SeekFrom::End(-(footer_prediction as i64)))
1162 .await
1163 .unwrap();
1164 let buf = &mut vec![0; footer_prediction as usize]; pithos_input.read_exact(buf).await.unwrap();
1166
1167 let mut parser = FooterParser::new(buf).unwrap();
1168 parser = parser.add_recipient(&privkey_2);
1169 parser = parser.parse().unwrap();
1170
1171 let footer: Footer = parser.try_into().unwrap();
1172 assert!(footer.encryption_keys.unwrap().keys.len() > 0)
1173 }
1174
1175 #[tokio::test]
1176 async fn e2e_pithos_extractor() {
1177 let temp_dir = TempDir::new().unwrap();
1179 let pithos_out_path = temp_dir.path().join("test.txt.pto");
1180 let mut pithos_out = File::create(&pithos_out_path).await.unwrap();
1181
1182 let input_file = File::open("test.txt").await.unwrap();
1183 let input_size = input_file.metadata().await.unwrap().len();
1184 let input_stream = tokio_util::io::ReaderStream::new(input_file)
1185 .map_err(|_| Box::<dyn std::error::Error + Send + Sync + 'static>::from("a_str_error"));
1186
1187 let privkey_bytes = BASE64_STANDARD
1189 .decode("MC4CAQAwBQYDK2VuBCIEIFDnbf0aEpZxwEdy1qG4xpV8gVNq7zEREtMjLzCE6R5x")
1190 .unwrap();
1191 let privkey: [u8; 32] = privkey_bytes[privkey_bytes.len() - 32..]
1192 .to_vec()
1193 .try_into()
1194 .unwrap();
1195
1196 let pubkey_bytes = BASE64_STANDARD
1197 .decode("MCowBQYDK2VuAyEA2laqNukb4+2am7QdC6eDANu1DDuKdC5LPtYQM+XE5k8=")
1198 .unwrap();
1199 let pubkey: [u8; 32] = pubkey_bytes[pubkey_bytes.len() - 32..]
1200 .to_vec()
1201 .try_into()
1202 .unwrap();
1203
1204 let (sx, rx) = async_channel::bounded(10);
1205 sx.send(Message::FileContext(FileContext {
1206 file_path: "file1.txt".to_string(),
1207 compressed_size: input_size,
1208 decompressed_size: input_size,
1209 recipients_pubkeys: vec![pubkey],
1210 encryption_key: EncryptionKey::Same(
1211 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
1212 .to_vec()
1213 .to_vec()
1214 .try_into()
1215 .unwrap(),
1216 ),
1217 ..Default::default()
1218 }))
1219 .await
1220 .unwrap();
1221
1222 let mut aswr = GenericStreamReadWriter::new_with_writer(input_stream, &mut pithos_out)
1224 .add_transformer(PithosTransformer::new())
1225 .add_transformer(FooterGenerator::new(None));
1226 aswr.add_message_receiver(rx).await.unwrap();
1227 aswr.process().await.unwrap();
1228
1229 let mut pithos_input = File::open(pithos_out_path).await.unwrap();
1231 let file_meta = pithos_input.metadata().await.unwrap();
1232
1233 let footer_prediction = if file_meta.len() < 65536 * 2 {
1234 file_meta.len() } else {
1236 65536 * 2
1237 };
1238
1239 pithos_input
1241 .seek(SeekFrom::End(-(footer_prediction as i64)))
1242 .await
1243 .unwrap();
1244 let buf = &mut vec![0; footer_prediction as usize];
1245 pithos_input.read_exact(buf).await.unwrap();
1246
1247 let mut parser = FooterParser::new(buf).unwrap();
1248 parser = parser.add_recipient(&privkey);
1249 parser = parser.parse().unwrap();
1250
1251 let footer: Footer = parser.try_into().unwrap();
1253
1254 let mut vec = Vec::new();
1256 pithos_input.seek(SeekFrom::Start(0)).await.unwrap();
1257 let input_stream = tokio_util::io::ReaderStream::new(pithos_input)
1258 .map_err(|_| Box::<dyn std::error::Error + Send + Sync + 'static>::from("a_str_error"));
1259
1260 let (extractor, rcv) = FooterExtractor::new(Some(privkey));
1261 GenericStreamReadWriter::new_with_writer(input_stream, &mut vec)
1262 .add_transformer(extractor)
1263 .process()
1264 .await
1265 .unwrap();
1266
1267 let extracted_footer = rcv.recv_blocking().unwrap();
1268 assert_eq!(extracted_footer, footer);
1269 }
1270
1271 #[tokio::test]
1272 async fn e2e_test_parts_decryptor() {
1273 let file = File::open("test.txt").await.unwrap();
1274 let file2 = vec![];
1275
1276 let repeated: Vec<u64> = vec![65564u64 * 60, 65564 * 16, 65564, 50860];
1277
1278 GenericReadWriter::new_with_writer(file, file2)
1280 .add_transformer(
1281 ChaCha20Enc::new_with_fixed(
1282 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
1283 .to_vec()
1284 .try_into()
1285 .unwrap(),
1286 )
1287 .unwrap(),
1288 )
1289 .add_transformer(ChaCha20DecParts::new_with_lengths(
1290 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
1291 .to_vec()
1292 .try_into()
1293 .unwrap(),
1294 repeated,
1295 ))
1296 .process()
1297 .await
1298 .unwrap();
1299 }
1300
1301 #[tokio::test]
1302 async fn e2e_test_resilient_decryptor_no_lengths() {
1303 let temp_dir = TempDir::new().unwrap();
1305 let enc_file_path = temp_dir.path().join("test.txt.enc");
1306
1307 let file_in = File::open("test.txt").await.unwrap();
1308 let mut enc_out = File::options()
1309 .create(true)
1310 .write(true)
1311 .truncate(true)
1312 .open(&enc_file_path)
1313 .await
1314 .unwrap();
1315
1316 GenericReadWriter::new_with_writer(file_in, &mut enc_out)
1317 .add_transformer(
1318 ChaCha20Enc::new_with_fixed(
1319 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
1320 .to_vec()
1321 .try_into()
1322 .unwrap(),
1323 )
1324 .unwrap(),
1325 )
1326 .process()
1327 .await
1328 .unwrap();
1329
1330 let mut input = Vec::new();
1332 let mut enc_file = File::open(enc_file_path).await.unwrap();
1333 enc_file.read_to_end(&mut input).await.unwrap();
1334
1335 let mut output = vec![];
1337 let part_lengths: Vec<u64> = vec![];
1338 GenericReadWriter::new_with_writer(input.as_slice(), &mut output)
1339 .add_transformer(ChaChaResilient::new_with_lengths(
1340 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
1341 .to_vec()
1342 .try_into()
1343 .unwrap(),
1344 part_lengths,
1345 ))
1346 .process()
1347 .await
1348 .unwrap();
1349
1350 let mut original_file = File::open("test.txt").await.unwrap();
1352 let file_size = original_file.metadata().await.unwrap().len();
1353 assert_eq!(output.len() as u64, file_size);
1354
1355 let mut original_bytes = Vec::new();
1356 original_file
1357 .read_to_end(&mut original_bytes)
1358 .await
1359 .unwrap();
1360 assert_eq!(output, original_bytes);
1361 }
1362
1363 #[tokio::test]
1364 async fn e2e_test_resilient_decryptor_single() {
1365 let temp_dir = TempDir::new().unwrap();
1367 let part_1_path = temp_dir.path().join("test.1.txt.enc");
1368 let mut part_1_out = File::create(&part_1_path).await.unwrap();
1369
1370 let mut input = File::open("test.txt").await.unwrap();
1371 let mut part_1_bytes = vec![0; 70113];
1372 input.read_exact(&mut part_1_bytes).await.unwrap();
1373
1374 GenericReadWriter::new_with_writer(part_1_bytes.as_ref(), &mut part_1_out)
1375 .add_transformer(
1376 ChaCha20Enc::new_with_fixed(
1377 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
1378 .to_vec()
1379 .try_into()
1380 .unwrap(),
1381 )
1382 .unwrap(),
1383 )
1384 .process()
1385 .await
1386 .unwrap();
1387
1388 let mut input = Vec::new();
1390 let mut file_part_1 = File::open(part_1_path).await.unwrap();
1391 file_part_1.read_to_end(&mut input).await.unwrap();
1392
1393 let mut output = vec![];
1394 let part_lengths: Vec<u64> = vec![part_1_bytes.len() as u64];
1395
1396 GenericReadWriter::new_with_writer(input.as_slice(), &mut output)
1398 .add_transformer(ChaChaResilient::new_with_lengths(
1399 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
1400 .to_vec()
1401 .try_into()
1402 .unwrap(),
1403 part_lengths,
1404 ))
1405 .process()
1406 .await
1407 .unwrap();
1408
1409 assert_eq!(output, part_1_bytes);
1410 }
1411
1412 #[tokio::test]
1413 async fn e2e_test_resilient_decryptor_multi() {
1414 let temp_dir = TempDir::new().unwrap();
1416 let part_1_path = temp_dir.path().join("test.1.txt.enc");
1417 let part_2_path = temp_dir.path().join("test.2.txt.enc");
1418 let mut input = File::open("test.txt").await.unwrap();
1419
1420 let mut part_1_bytes = vec![0; 70113];
1422 input.read_exact(&mut part_1_bytes).await.unwrap();
1423 let part_1_out = File::create(&part_1_path).await.unwrap();
1424
1425 let mut part_2_bytes = Vec::new();
1426 input.read_to_end(&mut part_2_bytes).await.unwrap();
1427 let part_2_out = File::create(&part_2_path).await.unwrap();
1428
1429 for (input, mut output) in vec![
1430 (part_1_bytes.as_ref(), part_1_out),
1431 (part_2_bytes.as_ref(), part_2_out),
1432 ] {
1433 GenericReadWriter::new_with_writer(input, &mut output)
1434 .add_transformer(
1435 ChaCha20Enc::new_with_fixed(
1436 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
1437 .to_vec()
1438 .try_into()
1439 .unwrap(),
1440 )
1441 .unwrap(),
1442 )
1443 .process()
1444 .await
1445 .unwrap();
1446 }
1447
1448 let mut input = Vec::new();
1450 let mut file_part_1 = File::open(part_1_path).await.unwrap();
1451 file_part_1.read_to_end(&mut input).await.unwrap();
1452 let mut file_part_2 = File::open(part_2_path).await.unwrap();
1453 file_part_2.read_to_end(&mut input).await.unwrap();
1454
1455 let mut output = vec![];
1456 let part_lengths: Vec<u64> = vec![4605, 46283];
1457
1458 GenericReadWriter::new_with_writer(input.as_slice(), &mut output)
1460 .add_transformer(ChaChaResilient::new_with_lengths(
1461 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
1462 .to_vec()
1463 .try_into()
1464 .unwrap(),
1465 part_lengths,
1466 ))
1467 .process()
1468 .await
1469 .unwrap();
1470
1471 let mut original_file = File::open("test.txt").await.unwrap();
1473 let file_size = original_file.metadata().await.unwrap().len();
1474 assert_eq!(output.len() as u64, file_size);
1475
1476 let mut original_bytes = Vec::new();
1477 original_file
1478 .read_to_end(&mut original_bytes)
1479 .await
1480 .unwrap();
1481 assert_eq!(output, original_bytes);
1482 }
1483
1484 #[tokio::test]
1485 async fn e2e_test_resilient_decryptor_multi_with_compression() {
1486 let temp_dir = TempDir::new().unwrap();
1488 let part_1_path = temp_dir.path().join("test.1.txt.enc");
1489 let part_2_path = temp_dir.path().join("test.2.txt.enc");
1490 let mut input = File::open("test.txt").await.unwrap();
1491
1492 let mut part_1_bytes = vec![0; 70113];
1494 input.read_exact(&mut part_1_bytes).await.unwrap();
1495 let part_1_out = File::create(&part_1_path).await.unwrap();
1496
1497 let mut part_2_bytes = Vec::new();
1498 input.read_to_end(&mut part_2_bytes).await.unwrap();
1499 let part_2_out = File::create(&part_2_path).await.unwrap();
1500
1501 for (input, mut output) in vec![
1502 (part_1_bytes.as_ref(), part_1_out),
1503 (part_2_bytes.as_ref(), part_2_out),
1504 ] {
1505 GenericReadWriter::new_with_writer(input, &mut output)
1506 .add_transformer(ZstdEnc::new())
1507 .add_transformer(
1508 ChaCha20Enc::new_with_fixed(
1509 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
1510 .to_vec()
1511 .try_into()
1512 .unwrap(),
1513 )
1514 .unwrap(),
1515 )
1516 .process()
1517 .await
1518 .unwrap();
1519 }
1520
1521 let mut input = Vec::new();
1523 let mut file_part_1 = File::open(part_1_path).await.unwrap();
1524 let file_part_1_size = file_part_1.metadata().await.unwrap().len();
1525 file_part_1.read_to_end(&mut input).await.unwrap();
1526
1527 let mut file_part_2 = File::open(part_2_path).await.unwrap();
1528 let file_part_2_size = file_part_2.metadata().await.unwrap().len();
1529 file_part_2.read_to_end(&mut input).await.unwrap();
1530
1531 let mut output = vec![];
1532 let part_lengths: Vec<u64> = vec![file_part_1_size % 65564, file_part_2_size % 65564]; GenericReadWriter::new_with_writer(input.as_slice(), &mut output)
1536 .add_transformer(ChaChaResilient::new_with_lengths(
1537 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
1538 .to_vec()
1539 .try_into()
1540 .unwrap(),
1541 part_lengths,
1542 ))
1543 .add_transformer(ZstdDec::new())
1544 .process()
1545 .await
1546 .unwrap();
1547
1548 let mut original_file = File::open("test.txt").await.unwrap();
1550 let file_size = original_file.metadata().await.unwrap().len();
1551 assert_eq!(output.len() as u64, file_size);
1552
1553 let mut original_bytes = Vec::new();
1554 original_file
1555 .read_to_end(&mut original_bytes)
1556 .await
1557 .unwrap();
1558 assert_eq!(output, original_bytes);
1559 }
1560
1561 #[tokio::test]
1562 async fn transformer_output_comparison() {
1563 let original_file = File::open("test.txt").await.unwrap();
1564 let file_size = original_file.metadata().await.unwrap().len();
1565
1566 let mut comp_enc_out = Vec::new();
1568 GenericReadWriter::new_with_writer(original_file, &mut comp_enc_out)
1569 .add_transformer(ZstdEnc::new())
1570 .add_transformer(
1571 ChaCha20Enc::new_with_fixed(
1572 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
1573 .to_vec()
1574 .to_vec()
1575 .try_into()
1576 .unwrap(),
1577 )
1578 .unwrap(),
1579 )
1580 .process()
1581 .await
1582 .unwrap();
1583
1584 let (sx, rx) = async_channel::bounded(10);
1586 sx.send(Message::FileContext(FileContext {
1587 file_path: "test.txt".to_string(),
1588 compressed_size: file_size,
1589 decompressed_size: file_size,
1590 recipients_pubkeys: vec![],
1591 encryption_key: EncryptionKey::Same(
1592 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
1593 .to_vec()
1594 .to_vec()
1595 .try_into()
1596 .unwrap(),
1597 ),
1598 ..Default::default()
1599 }))
1600 .await
1601 .unwrap();
1602
1603 let original_file = File::open("test.txt").await.unwrap();
1604 let mut pithos_out = Vec::new();
1605 let mut aswr = GenericReadWriter::new_with_writer(original_file, &mut pithos_out)
1606 .add_transformer(PithosTransformer::new());
1607 aswr.add_message_receiver(rx).await.unwrap();
1608 aswr.process().await.unwrap();
1609
1610 drop(aswr);
1611 let mut decrypted1 = Vec::new();
1614 GenericReadWriter::new_with_writer(comp_enc_out.as_slice(), &mut decrypted1)
1616 .add_transformer(ChaChaResilient::new_with_lengths(
1617 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
1618 .to_vec()
1619 .try_into()
1620 .unwrap(),
1621 vec![comp_enc_out.len() as u64],
1622 ))
1623 .add_transformer(ZstdDec::new())
1624 .process()
1625 .await
1626 .unwrap();
1627 assert_eq!(file_size, decrypted1.len() as u64);
1628
1629 let mut decrypted2 = Vec::new();
1630 GenericReadWriter::new_with_writer(pithos_out.as_slice(), &mut decrypted2)
1632 .add_transformer(ChaChaResilient::new_with_lengths(
1633 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
1634 .to_vec()
1635 .try_into()
1636 .unwrap(),
1637 vec![pithos_out.len() as u64],
1638 ))
1639 .add_transformer(ZstdDec::new())
1640 .process()
1641 .await
1642 .unwrap();
1643 assert_eq!(file_size, decrypted2.len() as u64);
1644
1645 assert_eq!(decrypted1, decrypted2);
1646 }
1647
1648 #[tokio::test]
1649 async fn e2e_test_resilient_decryptor_single_chunk() {
1650 let mut file_in = File::open("test.txt").await.unwrap();
1652 let mut file_bytes = Vec::new();
1653 file_in.read_to_end(&mut file_bytes).await.unwrap();
1654
1655 let encrypted_bytes =
1656 encrypt_chunk(&file_bytes, b"", b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea", false).unwrap();
1657
1658 let mut output = vec![];
1660 let part_lengths: Vec<u64> = vec![encrypted_bytes.len() as u64]; GenericReadWriter::new_with_writer(encrypted_bytes.to_vec().as_slice(), &mut output)
1662 .add_transformer(ChaChaResilient::new_with_lengths(
1663 b"wvwj3485nxgyq5ub9zd3e7jsrq7a92ea"
1664 .to_vec()
1665 .try_into()
1666 .unwrap(),
1667 part_lengths,
1668 ))
1669 .process()
1670 .await
1671 .unwrap();
1672
1673 assert_eq!(file_bytes.len(), output.len());
1675 assert_eq!(output, file_bytes);
1676 }
1677}