1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
use crate::feed_api::error::{FeedApiError, FeedApiErrorKind};
use failure::ResultExt;
use log::error;
use magic_crypt::{new_magic_crypt, MagicCryptTrait};
use rust_embed::RustEmbed;
use serde_derive::{Deserialize, Serialize};
use serde_json;
use std::str;

#[derive(RustEmbed)]
#[folder = "$OUT_DIR"]
struct KeyFile;

#[derive(Debug, Serialize, Deserialize)]
pub struct PasswordEncryption {
    password_crypt_key: String,
}

impl PasswordEncryption {
    pub fn encrypt(password: &str) -> Result<String, FeedApiError> {
        let key = Self::read_key()?;
        let crypt = new_magic_crypt!(key, 256);
        Ok(crypt.encrypt_str_to_base64(password))
    }

    pub fn decrypt(password: &str) -> Result<String, FeedApiError> {
        let key = Self::read_key()?;
        let crypt = new_magic_crypt!(key, 256);
        let password = crypt.decrypt_base64_to_string(password).map_err(|_| {
            error!("Failed to decrypt password: {}", password);
            FeedApiErrorKind::Encryption
        })?;
        Ok(password)
    }

    fn read_key() -> Result<String, FeedApiError> {
        let key_data = KeyFile::get("password_crypt_key.json").ok_or(FeedApiErrorKind::IO)?;
        let key_string = str::from_utf8(key_data.as_ref()).context(FeedApiErrorKind::IO)?;
        let key_struct: PasswordEncryption = serde_json::from_str(key_string).context(FeedApiErrorKind::Json)?;

        Ok(key_struct.password_crypt_key)
    }
}