1use std::fs;
2use std::fs::File;
3use std::io;
4use std::io::Write;
5
6mod funcs;
7
8const HELP: &str = "\n /l、
9(゚、 。 7
10 l ~ヽ
11 じしf_,)ノ\n\n\
12Welcome to hashkitten! 🐾\n\
13Your purrfect hashing companion.\n\n\
14Usage: hashkitten [-h] [-f FILE] [-c FILE|\"TEXT\" HASH] [\"TEXT\"]\n\
15A fun tool for hashing text or files.\n\n\
16ARGUMENTS\n\
17 -h | --help: Print help and exit\n\
18 -f | --file FILE [OUTPUT]: Hash the contents of the specified file. Optionally, write the hash to OUTPUT.\n\
19 -c | --compare FILE|\"TEXT\" HASH: Compare the contents of a file or a message to the specified hash.\n\
20 \"TEXT\": Input text to be hashed (must be enclosed in double quotes).\n\n\
21EXAMPLES\n\
22 hashkitten -h # Display help\n\
23 hashkitten -f input.txt # Hash the contents of input.txt\n\
24 hashkitten -f input.txt output.txt # Hash the contents of input.txt and write the hash to output.txt\n\
25 hashkitten -c input.txt HASH # Compare the hash of input.txt with HASH\n\
26 hashkitten -c \"Hello, world!\" HASH # Compare the hash of the message with HASH\n\
27 hashkitten \"Hello, world!\" # Hash the given text (must be in quotes)\n";
28
29pub fn meow_message(message: String) -> String {
30 let message_bytes = funcs::pre_processing(message);
31 let message_schedule = funcs::create_message_schedule(message_bytes);
32 let hash_values = funcs::compressing_schedule(message_schedule);
33 let sha256_hash = funcs::concatenate_hash(hash_values);
34 let meow = funcs::meow_from_hash(&sha256_hash);
35
36 meow
37}
38
39fn read_file(file_path: &String) -> Result<String, io::Error> {
40 match fs::read_to_string(file_path) {
41 Ok(val) => Ok(val),
42 Err(e) => Err(e),
43 }
44}
45
46pub fn run(args: Vec<String>) {
47 if args.len() < 2 {
48 eprintln!(
49 "*confused meow* No arguments provided! Use `-h` or `--help` for usage instructions."
50 );
51 return;
52 }
53
54 match args.get(1).map(|s| s.as_str()) {
55 Some("-h") | Some("--help") => {
56 println!("{}", HELP);
57 }
58
59 Some("-f") | Some("--file") => {
60 if args.len() < 3 {
61 eprintln!("*confused meow* Missing file path! Use `-f FILE` to specify a file.");
62 return;
63 }
64 let file_path = &args[2];
65 let output = args.get(3).map(String::from);
66 match read_file(file_path) {
67 Ok(contents) => {
68 let hash = meow_message(contents);
69 if let Some(output_path) = output {
70 match File::create(&output_path) {
71 Ok(mut file) => {
72 if let Err(e) = file.write_all(hash.as_bytes()) {
73 eprintln!(
74 "*surprised meow* Failed to write hash to file: {}",
75 e
76 );
77 }
78 }
79 Err(e) => {
80 eprintln!("*surprised meow* Failed to create file: {}", e);
81 }
82 }
83 } else {
84 println!("{}", hash);
85 }
86 }
87 Err(e) => {
88 eprintln!("*confused meow* Could not read file: {}", e);
89 }
90 }
91 }
92
93 Some("-c") | Some("--compare") => {
94 if args.len() < 4 {
95 eprintln!("*confused meow* Missing arguments for comparison! Use `-c \"MESSAGE\" HASH` or `-c FILE HASH`.");
96 return;
97 }
98
99 let input = args[2].clone();
100 let hash = args[3].clone();
101
102 let message = match read_file(&input) {
103 Ok(contents) => contents,
104 Err(_) => input,
105 };
106
107 let calculated_hash = meow_message(message);
108
109 if calculated_hash == hash {
110 println!("*excited purrs* Meow meow! The hash matches purrfectly! 🐱✨");
111 } else {
112 println!("*sad meow* The hash doesn't match! 🐱💔");
113 }
114 }
115
116 Some(_) => {
117 let message = args[1..].join(" ");
118 println!("{}", meow_message(message));
119 }
120
121 None => {
122 eprintln!("*confused meow* No valid arguments provided! Use `-h` for help.");
123 }
124 }
125}