sugar_cli/hash/
process.rs

1use std::{
2    fs::OpenOptions,
3    io::{BufReader, Read},
4};
5
6use console::style;
7use sha2::{Digest, Sha256};
8
9use crate::{
10    common::*,
11    config::{get_config_data, ConfigData, HiddenSettings},
12};
13
14pub struct HashArgs {
15    pub config: String,
16    pub cache: String,
17    pub compare: Option<String>,
18}
19
20pub fn process_hash(args: HashArgs) -> Result<()> {
21    let mut config_data = get_config_data(&args.config)?;
22
23    // We use std::process::exit to exit the program without going to the main handling which prints
24    // "Command successful".
25
26    if let Some(hash) = args.compare {
27        let mut hasher = Sha256::new();
28
29        let cache_file = File::open(args.cache)?;
30        let mut reader = BufReader::new(cache_file);
31        let mut buffer = Vec::new();
32        // Read file into vector.
33        reader.read_to_end(&mut buffer)?;
34
35        hasher.update(&buffer);
36        let hash_base58 = bs58::encode(&hasher.finalize()).into_string();
37        let expected_hash = hash_base58.chars().take(32).collect::<String>();
38        if hash != expected_hash {
39            println!(
40                "{} {}",
41                ERROR_EMOJI,
42                style("Hashes do not match!").red().bold()
43            );
44            std::process::exit(0);
45        }
46        println!(
47            "{} {}",
48            COMPLETE_EMOJI,
49            style("Hashes match!").blue().bold()
50        );
51        std::process::exit(0);
52    }
53
54    if let Some(ref hidden_settings) = config_data.hidden_settings {
55        println!(
56            "hash: {}",
57            hash_and_update(
58                hidden_settings.clone(),
59                &args.config,
60                &mut config_data,
61                &args.cache,
62            )?
63        );
64        println!(
65            "{} {}",
66            COMPLETE_EMOJI,
67            style("Config file updated with hash!").blue().bold()
68        );
69        std::process::exit(0);
70    } else {
71        Err(anyhow!("No hidden settings found in config file."))
72    }
73}
74
75pub fn hash_and_update(
76    mut hidden_settings: HiddenSettings,
77    config_file: &str,
78    config_data: &mut ConfigData,
79    cache_file_path: &str,
80) -> Result<String> {
81    let mut hasher = Sha256::new();
82
83    let cache_file = File::open(cache_file_path)?;
84    let mut reader = BufReader::new(cache_file);
85    let mut buffer = Vec::new();
86    // Read file into vector.
87    reader.read_to_end(&mut buffer)?;
88
89    hasher.update(&buffer);
90    let hash_base58 = bs58::encode(&hasher.finalize()).into_string();
91
92    let hash = hash_base58.chars().take(32).collect::<String>();
93    // Candy machine only allows for 32 characters so we truncate this hash.
94    hidden_settings.set_hash(hash.clone());
95    config_data.hidden_settings = Some(hidden_settings);
96
97    let file = OpenOptions::new()
98        .write(true)
99        .create(true)
100        .truncate(true)
101        .open(Path::new(&config_file))?;
102
103    serde_json::to_writer_pretty(file, &config_data)?;
104
105    Ok(hash)
106}