Skip to content

Commit

Permalink
Add configuration encryption function.
Browse files Browse the repository at this point in the history
  • Loading branch information
gudaoxuri committed Jul 5, 2022
1 parent 8b2f3a0 commit ddba265
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 10 deletions.
6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "tardis"
version = "0.1.0-alpha13"
.version = "0.1.0-alpha14"
authors = ["gudaoxuri <i@sunisle.org>"]
description = "Elegant, clean Rust development framework"
keywords = ["http", "database", "web", "redis", "mq"]
Expand Down Expand Up @@ -115,6 +115,10 @@ testcontainers = { version = "^0.14", optional = true }
tokio = { version = "^1.18", features = ["time", "rt", "macros"] }
criterion = { version = "^0.3" }

[[test]]
name = "test_basic_config"
required-features = ["crypto"]

[[test]]
name = "test_basic_crypto"
required-features = ["crypto", "crypto_with_sm"]
Expand Down
46 changes: 42 additions & 4 deletions src/basic/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use std::fmt::Debug;
use std::path::Path;

use config::{Config, ConfigError, Environment, File};
use regex::{Captures, Regex};
use serde_json::Value;

use crate::basic::error::{TardisError, ERROR_DEFAULT_CODE};
Expand Down Expand Up @@ -665,6 +666,16 @@ pub struct AdvConfig {
///
/// 启用后可方便定位错误,但会影响性能.
pub backtrace: bool,

/// Configure field encryption salt value / 配置字段加密盐值
///
/// Using the aes-ecb algorithm, salt consists of 16-bit English or numeric characters.
///
/// Usage:
/// . Open https://www.javainuse.com/aesgenerator and output the following:
/// `Enter Plain Text to Encrypt ` = `Value to be encrypted` , `Select Mode` = `ECB` , `Key Size in Bits` = `128` , `Enter Secret Key` = `Value of this field` , `Output Text Format` = `Hex`
/// . Click `Encrypt` to wrap the generated value in `ENC(xx)` to replace the original value
pub salt: String,
}

impl TardisConfig {
Expand Down Expand Up @@ -720,10 +731,37 @@ impl TardisConfig {
);
debug!("=====[Tardis.Config] Content=====\n{:#?}\n=====", framework_config);

Ok(TardisConfig {
cs: workspace_config,
fw: framework_config,
})
if framework_config.adv.salt.is_empty() {
Ok(TardisConfig {
cs: workspace_config,
fw: framework_config,
})
} else {
// decryption processing
let salt = framework_config.adv.salt.clone();
if salt.len() != 16 {
return Err(TardisError::FormatError("[Tardis.Config] [salt] length must be 16".to_string()));
}
fn decryption(text: &str, salt: &str) -> String {
let enc_r = Regex::new(r"(?P<ENC>ENC\([A-Za-z0-9+/]*\))").unwrap();
enc_r
.replace_all(text, |captures: &Captures| {
let data = captures.get(1).map_or("", |m| m.as_str()).to_string();
let data = &data[4..data.len() - 1];
TardisFuns::crypto.aes.decrypt_ecb(data, salt).expect("[Tardis.Config] Decryption error")
})
.to_string()
}

let wc = decryption(&TardisFuns::json.obj_to_string(&workspace_config)?, &salt);
let fw = decryption(&TardisFuns::json.obj_to_string(&framework_config)?, &salt);
let workspace_config = TardisFuns::json.str_to_obj(&wc)?;
let framework_config = TardisFuns::json.str_to_obj(&fw)?;
Ok(TardisConfig {
cs: workspace_config,
fw: framework_config,
})
}
}
}

Expand Down
7 changes: 5 additions & 2 deletions tests/config/conf-prod.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
url = "postgres://postgres@prod.proj"
[csm.m1]
[csm.m1.db_proj]
url = "postgres://postgres@m1.proj"
url = "ENC(9EE184E87EA31E6588C08BBC0F7C0E276DE482F7CEE914CBDA05DF619607A24E)"

[fw]
[fw.db]
url = "postgres://postgres@prod"
url = "ENC(9EE184E87EA31E6588C08BBC0F7C0E270BD6B3A21CDB32B06273DC96C5D24E51)"

[fw.adv]
salt = "16a80c4aea768c99"
17 changes: 17 additions & 0 deletions tests/test_basic_config.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// https://github.com/mehcode/config-rs

use regex::{Captures, Regex};
use std::env;

use tardis::basic::result::TardisResult;
Expand All @@ -10,6 +11,7 @@ use tardis::TardisFuns;
async fn test_basic_config() -> TardisResult<()> {
env::set_var("PROFILE", "test");
TardisFuns::init("tests/config").await?;
env::set_var("Tardis_FW.ADV.SALT", "16a80c4aea768c98");
assert_eq!(TardisFuns::cs_config::<TestConfig>("").project_name, "测试");
assert!(!TardisFuns::fw_config().db.enabled);
assert_eq!(TardisFuns::fw_config().db.url, "postgres://postgres@test");
Expand All @@ -18,6 +20,7 @@ async fn test_basic_config() -> TardisResult<()> {

env::set_var("PROFILE", "prod");
TardisFuns::init("tests/config").await?;
env::set_var("Tardis_FW.ADV.SALT", "16a80c4aea768c98");
assert_eq!(TardisFuns::fw_config().db.url, "postgres://postgres@prod");
assert_eq!(TardisFuns::cs_config::<TestConfig>("").db_proj.url, "postgres://postgres@prod.proj");
assert_eq!(TardisFuns::fw_config().app.name, "Tardis Application");
Expand All @@ -32,6 +35,20 @@ async fn test_basic_config() -> TardisResult<()> {
Ok(())
}

#[tokio::test]
async fn test_crypto_config() -> TardisResult<()> {
let re = Regex::new(r"(?P<ENC>ENC\([A-Za-z0-9+/]*\))").unwrap();
let before = r#"{"fw":{"app":{"name":"Hi{x}(a)"},"ak":"ENC(32ns9+s2/3df2v343)"},"sk":"ENC(4ewk2fsmd2)"}"#;
let after = re.replace_all(before, |captures: &Captures| {
let some = captures.get(1).map_or("", |m| m.as_str()).to_string();
println!("{}", some);
"1234"
});
assert_eq!(after, r#"{"fw":{"app":{"name":"Hi{x}(a)"},"ak":"1234"},"sk":"1234"}"#);

Ok(())
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(default)]
struct TestConfig {
Expand Down
19 changes: 16 additions & 3 deletions tests/test_basic_crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ use tardis::TardisFuns;

#[tokio::test]
async fn test_basic_crypto() -> TardisResult<()> {
let hex_str = TardisFuns::crypto.hex.encode("测试".as_bytes());
let str = TardisFuns::crypto.hex.decode(hex_str)?;
assert_eq!(str, "测试".as_bytes());

let b64_str = TardisFuns::crypto.base64.encode("测试");
let str = TardisFuns::crypto.base64.decode(&b64_str)?;
assert_eq!(str, "测试");
Expand All @@ -17,11 +21,14 @@ async fn test_basic_crypto() -> TardisResult<()> {
TardisFuns::crypto.digest.sha512("测试")?,
"98fb26ea83ce0f08918c967392a26ab298740aff3c18d032983b88bcee2e16d152ef372778259ebd529ed01701ff01ac4c95ed94e3a1ab9272ab98daf11f076c"
);
assert_eq!(TardisFuns::crypto.digest.hmac_sha1("测试", "pwd")?, "0e+vxZN90mgzsju6KCbS2EJ8Us4=");
assert_eq!(TardisFuns::crypto.digest.hmac_sha256("测试", "pwd")?, "4RnnEGA9fWaf/4mnWSQbJsdtsCXeXdUddSZUmXe6qn4=");
assert_eq!(TardisFuns::crypto.digest.hmac_sha1("测试", "pwd")?, "d1efafc5937dd26833b23bba2826d2d8427c52ce");
assert_eq!(
TardisFuns::crypto.digest.hmac_sha256("测试", "pwd")?,
"e119e710603d7d669fff89a759241b26c76db025de5dd51d7526549977baaa7e"
);
assert_eq!(
TardisFuns::crypto.digest.hmac_sha512("测试", "pwd")?,
"wO2937bb3tY/zLxUped257He0QMWywTsyhf2ELB3YWJmCgN4rS5a6+yWS852MC1LZ5HRd3AQjlUSOUUYKk0p9w=="
"c0edbddfb6dbded63fccbc54a5e776e7b1ded10316cb04ecca17f610b0776162660a0378ad2e5aebec964bce76302d4b6791d17770108e55123945182a4d29f7"
);

let large_text = "为什么选择 Rust?
Expand All @@ -42,6 +49,12 @@ Rust 拥有出色的文档、友好的编译器和清晰的错误提示信息,
// let key = TardisFuns::crypto.key.rand_32_hex()?;
// let iv = TardisFuns::crypto.key.rand_16_hex()?;

let key = TardisFuns::crypto.key.rand_16_hex()?;

let encrypted_data = TardisFuns::crypto.aes.encrypt_ecb(large_text, &key)?;
let data = TardisFuns::crypto.aes.decrypt_ecb(&encrypted_data, &key)?;
assert_eq!(data, large_text);

let key = TardisFuns::crypto.key.rand_16_hex()?;
let iv = TardisFuns::crypto.key.rand_16_hex()?;

Expand Down

0 comments on commit ddba265

Please sign in to comment.