meta_secret_core/
lib.rs

1extern crate core;
2
3use std::ffi::OsStr;
4use std::fs::File;
5use std::io::BufReader;
6use std::path::Path;
7use std::{fs, io};
8
9use crate::errors::CoreError;
10use errors::{RecoveryError, SharesLoaderError, SplitError};
11use image::ImageError;
12use rqrr::DeQRError;
13
14use crate::shared_secret::data_block::common::SharedSecretConfig;
15use crate::shared_secret::data_block::shared_secret_data_block::SharedSecretBlock;
16use crate::shared_secret::shared_secret::{PlainText, SharedSecret, SharedSecretEncryption, UserShareDto};
17use errors::RecoveryError::EmptyInput;
18
19pub mod crypto;
20pub mod errors;
21pub mod node;
22pub mod sdk;
23pub mod shared_secret;
24pub mod models;
25
26#[macro_use]
27extern crate serde_derive;
28
29extern crate serde;
30extern crate serde_json;
31
32pub type CoreResult<T> = std::result::Result<T, CoreError>;
33
34#[derive(Debug, thiserror::Error)]
35pub enum RecoveryOperationError {
36    #[error(transparent)]
37    LoaderError(#[from] SharesLoaderError),
38    #[error(transparent)]
39    RecoveryFromSharesError(#[from] RecoveryError),
40}
41
42pub fn recover() -> CoreResult<PlainText> {
43    let users_shares = load_users_shares()?;
44    let recovered = recover_from_shares(users_shares)?;
45    Ok(recovered)
46}
47
48pub fn recover_from_shares(users_shares: Vec<UserShareDto>) -> CoreResult<PlainText> {
49    let mut secret_blocks: Vec<SharedSecretBlock> = vec![];
50
51    if users_shares[0].share_blocks.is_empty() {
52        let err = EmptyInput("Empty shares list. Nothing to recover".to_string());
53        return Err(CoreError::from(err));
54    }
55
56    let blocks_num: usize = users_shares[0].share_blocks.len();
57
58    for block_index in 0..blocks_num {
59        let mut encrypted_data_blocks = vec![];
60
61        for user_share in users_shares.iter() {
62            let encrypted_data_block = user_share.get_encrypted_data_block(block_index)?;
63            encrypted_data_blocks.push(encrypted_data_block);
64        }
65
66        let curr_block = &users_shares[0].share_blocks[block_index];
67        let secret_block = SharedSecretBlock {
68            config: curr_block.config,
69            meta_data: curr_block.meta_data.clone(),
70            shares: encrypted_data_blocks,
71        };
72
73        secret_blocks.push(secret_block);
74    }
75
76    let secret = SharedSecret { secret_blocks };
77
78    let result = secret.recover()?;
79    Ok(result)
80}
81
82fn load_users_shares() -> Result<Vec<UserShareDto>, SharesLoaderError> {
83    //read json files
84    let shares = fs::read_dir("secrets")?;
85
86    let mut users_shares_dto: Vec<UserShareDto> = vec![];
87    for secret_share_file in shares {
88        let file_path = secret_share_file?.path();
89
90        let maybe_ext = file_path.extension().and_then(OsStr::to_str);
91
92        if let Some(ext) = maybe_ext {
93            if ext.eq("json") {
94                // Open the file in read-only mode with buffer.
95                let file = File::open(file_path)?;
96                let reader = BufReader::new(file);
97
98                // Read the JSON contents of the file as an instance of `User`.
99                let secret_share: UserShareDto = serde_json::from_reader(reader)?;
100                users_shares_dto.push(secret_share);
101            }
102        }
103    }
104
105    Ok(users_shares_dto)
106}
107
108pub fn split(secret: String, config: SharedSecretConfig) -> CoreResult<()> {
109    let plain_text = PlainText::from(secret);
110    let shared_secret = SharedSecretEncryption::new(config, &plain_text)?;
111
112    let dir_op = fs::create_dir_all("secrets");
113
114    if let Err(dir_err) = dir_op {
115        return Err(CoreError::from(SplitError::from(dir_err)));
116    }
117
118    for share_index in 0..config.number_of_shares {
119        let share: UserShareDto = shared_secret.get_share(share_index);
120        let share_json = serde_json::to_string_pretty(&share)?;
121
122        // Save the JSON structure into the output file
123        let write_op = fs::write(format!("secrets/shared-secret-{share_index}.json"), share_json.clone());
124
125        if let Err(op_err) = write_op {
126            return Err(CoreError::from(SplitError::from(op_err)));
127        }
128
129        //generate qr code
130        generate_qr_code(
131            share_json.as_str(),
132            format!("secrets/shared-secret-{share_index}.png").as_str(),
133        )
134    }
135
136    Ok(())
137}
138
139pub fn generate_qr_code(data: &str, path: &str) {
140    use qrcode_generator::QrCodeEcc;
141
142    qrcode_generator::to_png_to_file(data, QrCodeEcc::High, data.len(), path).unwrap();
143}
144
145#[derive(Debug, thiserror::Error)]
146pub enum QrToJsonParserError {
147    #[error(
148        "Secrets directory has invalid structure. \
149        Please check that 'secrets' dir exists and \
150        contains json or qr files with password shares"
151    )]
152    SecretsDirectoryError {
153        #[from]
154        source: io::Error,
155    },
156    #[error("Image parsing error")]
157    ImageParsingError {
158        #[from]
159        source: QrCodeParserError,
160    },
161}
162
163pub fn convert_qr_images_to_json_files() -> Result<Vec<String>, QrToJsonParserError> {
164    let shares = fs::read_dir("secrets")?;
165
166    let mut shares_json: Vec<String> = vec![];
167
168    let mut share_index = 0;
169    for secret_share_file in shares {
170        let file_path = secret_share_file?.path();
171
172        let extension = file_path.extension().and_then(OsStr::to_str).unwrap();
173
174        if !extension.eq("png") {
175            continue;
176        }
177
178        let json_str = read_qr_code(file_path.as_path())?;
179        fs::write(format!("secrets/shared-secret-{share_index}.json"), json_str.clone())?;
180
181        shares_json.push(json_str.clone());
182
183        share_index += 1;
184    }
185
186    Ok(shares_json)
187}
188
189#[derive(Debug, thiserror::Error)]
190pub enum QrCodeParserError {
191    #[error("Qr code parsing error")]
192    ImageParsingError {
193        #[from]
194        source: ImageError,
195    },
196    #[error("Error decoding image")]
197    ImageDecodingError {
198        #[from]
199        source: DeQRError,
200    },
201}
202
203pub fn read_qr_code(path: &Path) -> Result<String, QrCodeParserError> {
204    let img = image::open(path)?.to_luma8();
205    // Prepare for detection
206    let mut img = rqrr::PreparedImage::prepare(img);
207    // Search for grids, without decoding
208    let grids = img.detect_grids();
209    assert_eq!(grids.len(), 1);
210    // Decode the grid
211    let (_, content) = grids[0].decode()?;
212    Ok(content)
213}