Skip to main content

i6_pack/
cli.rs

1use std::io::Write;
2use std::path::PathBuf;
3
4use crate::compression;
5use crate::encryptions;
6use crate::utils;
7
8use crate::encryptions::encryption::Encryption;
9
10pub fn run(action: &str, target: &str, encrypt: bool) -> std::io::Result<()> {
11  let password = &if encrypt {
12    print!("Enter password: ");
13    std::io::stdout().flush().expect("Failed to flush stdout");
14    let password1 =
15      rpassword::read_password().expect("Failed to read password");
16
17    if (action == "pack") {
18      print!("Confirm password: ");
19      std::io::stdout().flush().expect("Failed to flush stdout");
20      let password2 =
21        rpassword::read_password().expect("Failed to read password");
22
23      if password1 != password2 {
24        eprintln!("Passwords do not match.");
25        std::process::exit(1);
26      }
27    }
28
29    password1
30  } else {
31    "".to_owned()
32  };
33
34  // Validate and sanitize the target path
35  let target_path = utils::validate_path(target)
36    .or_else(|_| utils::sanitize_output_path(target))
37    .expect("Invalid target path");
38
39  return run_non_interactive(
40    action,
41    target_path.to_str().unwrap_or_default(),
42    password,
43  );
44}
45
46pub fn run_non_interactive(
47  action: &str,
48  target: &str,
49  password: &str,
50) -> std::io::Result<()> {
51  let encrypt = !password.is_empty();
52  let extension = if encrypt { "i6pe" } else { "i6p" };
53
54  let target_path = PathBuf::from(target);
55
56  let tar_file =
57    &format!("{}-{}.tar", target_path.display(), uuid::Uuid::new_v4());
58  let compressed_file =
59    &format!("{}-{}.tar.zst", target_path.display(), uuid::Uuid::new_v4());
60
61  let file_out = &format!("{}.{}", target_path.display(), extension);
62
63  match action {
64    "pack" => {
65      compression::create_tar_archive(target_path.to_str().unwrap(), tar_file)?;
66
67      if (encrypt) {
68        compression::compress_tar_file(tar_file, compressed_file)?;
69        encryptions::cha_cha20_poly1305::ChaCha20Poly1305::encrypt_file(
70          compressed_file,
71          file_out,
72          password,
73        )?;
74      } else {
75        compression::compress_tar_file(tar_file, file_out)?;
76      }
77    }
78    "unpack" => {
79      if (encrypt) {
80        encryptions::cha_cha20_poly1305::ChaCha20Poly1305::decrypt_file(
81          target_path.to_str().unwrap(),
82          compressed_file,
83          password,
84        )?;
85        compression::decompress_file(compressed_file, tar_file)?;
86      } else {
87        compression::decompress_file(target_path.to_str().unwrap(), tar_file)?;
88      }
89
90      compression::extract_tar_archive(
91        tar_file,
92        &utils::remove_extension(
93          target_path.to_str().unwrap(),
94          &format!(".{extension}"),
95        ),
96      )?;
97    }
98    _ => {
99      eprintln!("Invalid action. Use 'pack' or 'unpack'.");
100      std::process::exit(1);
101    }
102  }
103
104  // Clean up temporary files
105  std::fs::remove_file(tar_file)?;
106
107  if (encrypt) {
108    std::fs::remove_file(compressed_file)?;
109  }
110
111  Ok(())
112}