implemented encryption and decryption
This commit is contained in:
parent
bba1912507
commit
a0a140fc0b
24
.vscode/launch.json
vendored
24
.vscode/launch.json
vendored
@ -22,6 +22,30 @@
|
|||||||
"args": [],
|
"args": [],
|
||||||
"cwd": "${workspaceFolder}"
|
"cwd": "${workspaceFolder}"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "lldb",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Debug (auto-decrypt)",
|
||||||
|
"program": "${workspaceFolder}/target/debug/auto-decrypt",
|
||||||
|
"cargo": {
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"--bin=auto-decrypt",
|
||||||
|
"--package=auto-decrypt"
|
||||||
|
],
|
||||||
|
"filter": {
|
||||||
|
"name": "auto-decrypt",
|
||||||
|
"kind": "bin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"args": [
|
||||||
|
"--get-key",
|
||||||
|
"hello_world",
|
||||||
|
"--provider",
|
||||||
|
"debug_config/enc/test_provider.toml"
|
||||||
|
],
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "lldb",
|
"type": "lldb",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
|
|||||||
52
Cargo.lock
generated
52
Cargo.lock
generated
@ -236,6 +236,7 @@ dependencies = [
|
|||||||
"reqwest",
|
"reqwest",
|
||||||
"rocket",
|
"rocket",
|
||||||
"rocket_dyn_templates",
|
"rocket_dyn_templates",
|
||||||
|
"rusqlite",
|
||||||
"serde",
|
"serde",
|
||||||
"toml",
|
"toml",
|
||||||
"url",
|
"url",
|
||||||
@ -945,6 +946,18 @@ dependencies = [
|
|||||||
"windows-sys 0.60.2",
|
"windows-sys 0.60.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fallible-iterator"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fallible-streaming-iterator"
|
||||||
|
version = "0.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
version = "2.3.0"
|
version = "2.3.0"
|
||||||
@ -1263,12 +1276,30 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.14.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||||
|
dependencies = [
|
||||||
|
"ahash",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.15.4"
|
version = "0.15.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
|
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashlink"
|
||||||
|
version = "0.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af"
|
||||||
|
dependencies = [
|
||||||
|
"hashbrown 0.14.5",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
@ -1640,7 +1671,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
|
checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown",
|
"hashbrown 0.15.4",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1822,10 +1853,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libsqlite3-sys"
|
name = "libsqlite3-sys"
|
||||||
version = "0.35.0"
|
version = "0.30.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "133c182a6a2c87864fe97778797e46c7e999672690dc9fa3ee8e241aa4a9c13f"
|
checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"cc",
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
"vcpkg",
|
"vcpkg",
|
||||||
]
|
]
|
||||||
@ -2756,6 +2788,20 @@ dependencies = [
|
|||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rusqlite"
|
||||||
|
version = "0.32.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.9.1",
|
||||||
|
"fallible-iterator",
|
||||||
|
"fallible-streaming-iterator",
|
||||||
|
"hashlink",
|
||||||
|
"libsqlite3-sys",
|
||||||
|
"smallvec",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "russh"
|
name = "russh"
|
||||||
version = "0.51.1"
|
version = "0.51.1"
|
||||||
|
|||||||
@ -21,3 +21,4 @@ diesel-derive-enum = { version = "3.0.0-beta.1", features = ["sqlite"] }
|
|||||||
argon2 = "0.5.3"
|
argon2 = "0.5.3"
|
||||||
base64 = "0.22.1"
|
base64 = "0.22.1"
|
||||||
chacha20poly1305 = "0.10.1"
|
chacha20poly1305 = "0.10.1"
|
||||||
|
rusqlite = { version = "0.32", features = ["bundled"] }
|
||||||
20
shell.nix
20
shell.nix
@ -1,5 +1,5 @@
|
|||||||
let
|
let
|
||||||
# Import nixpkgs and add the mozilla overlay
|
# Import nixpkgs and add the Mozilla overlay
|
||||||
nixpkgs = import <nixpkgs> {
|
nixpkgs = import <nixpkgs> {
|
||||||
overlays = [
|
overlays = [
|
||||||
(import (builtins.fetchTarball {
|
(import (builtins.fetchTarball {
|
||||||
@ -12,21 +12,31 @@ nixpkgs.mkShell {
|
|||||||
buildInputs = [
|
buildInputs = [
|
||||||
((nixpkgs.rustChannelOf {
|
((nixpkgs.rustChannelOf {
|
||||||
channel = "stable";
|
channel = "stable";
|
||||||
date = null; # null means latest
|
date = null; # null = latest stable channel
|
||||||
}).rust.override {
|
}).rust.override {
|
||||||
extensions = [ "rust-src" "rust-analysis" ];
|
extensions = [ "rust-src" "rust-analysis" ];
|
||||||
})
|
})
|
||||||
|
|
||||||
nixpkgs.openssl
|
nixpkgs.openssl
|
||||||
nixpkgs.pkg-config
|
nixpkgs.pkg-config
|
||||||
nixpkgs.sqlite
|
nixpkgs.sqlite
|
||||||
nixpkgs.libpq
|
nixpkgs.libpq
|
||||||
|
nixpkgs.lldb
|
||||||
nixpkgs.libmysqlclient
|
nixpkgs.libmysqlclient
|
||||||
];
|
];
|
||||||
|
|
||||||
shellHook = ''
|
shellHook = ''
|
||||||
export TMPDIR=/tmp
|
export TMPDIR=/tmp
|
||||||
export PATH=$PATH:$HOME/.cargo/bin
|
export PATH=$PATH:$HOME/.cargo/bin
|
||||||
cargo install diesel_cli
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
# Ensure dynamic linker can find required libs (SQLite, OpenSSL, PostgreSQL, MySQL)
|
||||||
|
export LD_LIBRARY_PATH=${nixpkgs.openssl.out}/lib:${nixpkgs.sqlite.out}/lib:${nixpkgs.libpq.out}/lib:${nixpkgs.libmysqlclient.out}/lib:$LD_LIBRARY_PATH
|
||||||
|
|
||||||
|
|
||||||
|
# Install diesel_cli if not already installed
|
||||||
|
if ! command -v diesel >/dev/null 2>&1; then
|
||||||
|
echo "Installing diesel_cli (SQLite)..."
|
||||||
|
cargo install diesel_cli --no-default-features --features "sqlite"
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
|||||||
@ -30,7 +30,7 @@ pub(crate) fn consent(consent_id: i32, db_conn: &State<DbConn>) -> Result<Templa
|
|||||||
|
|
||||||
|
|
||||||
#[derive(FromForm)]
|
#[derive(FromForm)]
|
||||||
struct ConsentInput {
|
pub(crate) struct ConsentInput {
|
||||||
key: Option<String>,
|
key: Option<String>,
|
||||||
rejected: bool,
|
rejected: bool,
|
||||||
}
|
}
|
||||||
@ -86,7 +86,7 @@ pub(crate) async fn consent_post<'a>(
|
|||||||
Ok(msg) => (RecordStates::Accepted, UserMessage { level: MessageType::Success, message: msg }),
|
Ok(msg) => (RecordStates::Accepted, UserMessage { level: MessageType::Success, message: msg }),
|
||||||
Err(err) => (RecordStates::Failed, UserMessage { level: MessageType::Danger, message: err.to_string() }),
|
Err(err) => (RecordStates::Failed, UserMessage { level: MessageType::Danger, message: err.to_string() }),
|
||||||
};
|
};
|
||||||
|
println!("{:?}", message.message);
|
||||||
record = db_conn.update_provider_state(record.id, new_state);
|
record = db_conn.update_provider_state(record.id, new_state);
|
||||||
Ok(render_consent(&record, Some(message)))
|
Ok(render_consent(&record, Some(message)))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,7 +25,7 @@ impl<'r> FromRequest<'r> for APIProviderRequest<'r> {
|
|||||||
let path = req.uri().path().segments();
|
let path = req.uri().path().segments();
|
||||||
let share_name: &str = path.get(path.len() - 1).unwrap_or(&"");
|
let share_name: &str = path.get(path.len() - 1).unwrap_or(&"");
|
||||||
|
|
||||||
let access_key: &str = &get_query_value(&req.uri().query(), "trigger_key")
|
let access_key: &str = &get_query_value(&req.uri().query(), "access_key")
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
if share_name.is_empty() {
|
if share_name.is_empty() {
|
||||||
@ -38,7 +38,7 @@ impl<'r> FromRequest<'r> for APIProviderRequest<'r> {
|
|||||||
Outcome::Success(APIProviderRequest { share: service.1, name: service.0 })
|
Outcome::Success(APIProviderRequest { share: service.1, name: service.0 })
|
||||||
} else {
|
} else {
|
||||||
Outcome::Error(HttpResult::ShareNotFound(format!(
|
Outcome::Error(HttpResult::ShareNotFound(format!(
|
||||||
"Share '{}' not found.",
|
"Share '{}' not found or access_key invalide.",
|
||||||
share_name
|
share_name
|
||||||
)).into())
|
)).into())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,6 +25,7 @@ pub(crate) struct AppConfig {
|
|||||||
pub(crate) user_confirmation_expiration: i64,
|
pub(crate) user_confirmation_expiration: i64,
|
||||||
pub(crate) db_file: String,
|
pub(crate) db_file: String,
|
||||||
pub(crate) crypto_key: String,
|
pub(crate) crypto_key: String,
|
||||||
|
pub(crate) base_config_dir: String,
|
||||||
|
|
||||||
pub(crate) beggars: HashMap<String, Beggars>, // We request to unlock owned services
|
pub(crate) beggars: HashMap<String, Beggars>, // We request to unlock owned services
|
||||||
pub(crate) providers: HashMap<String, Providers>, // We offer to unlock these services
|
pub(crate) providers: HashMap<String, Providers>, // We offer to unlock these services
|
||||||
@ -42,6 +43,7 @@ impl Default for AppConfig {
|
|||||||
platform: Platform::OMV,
|
platform: Platform::OMV,
|
||||||
ssh_known_host_file: "".to_string(),
|
ssh_known_host_file: "".to_string(),
|
||||||
db_file: "/var/auto-decrypt/db.sqlite".to_string(),
|
db_file: "/var/auto-decrypt/db.sqlite".to_string(),
|
||||||
|
base_config_dir: "".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -58,12 +60,24 @@ impl AppConfig {
|
|||||||
user_confirmation_expiration: toml_config.user_confirmation_expiration.unwrap_or(default.user_confirmation_expiration),
|
user_confirmation_expiration: toml_config.user_confirmation_expiration.unwrap_or(default.user_confirmation_expiration),
|
||||||
ssh_known_host_file: toml_config.ssh_known_host_file.unwrap_or(default.ssh_known_host_file),
|
ssh_known_host_file: toml_config.ssh_known_host_file.unwrap_or(default.ssh_known_host_file),
|
||||||
db_file: toml_config.db_file.unwrap_or(default.db_file),
|
db_file: toml_config.db_file.unwrap_or(default.db_file),
|
||||||
|
base_config_dir: base_config_dir.to_str().unwrap_or(default.base_config_dir.as_str()).to_string(),
|
||||||
beggars: toml_config.beggars.unwrap_or(default.beggars),
|
beggars: toml_config.beggars.unwrap_or(default.beggars),
|
||||||
providers: toml_config.providers.and_then(|providers|
|
providers: toml_config.providers
|
||||||
Some(providers.into_iter().map(|(name, service)|
|
.map(|providers| {
|
||||||
(name, service.to_internal(base_config_dir).expect("Err"))
|
providers
|
||||||
).collect::<HashMap<String, Providers>>())
|
.into_iter()
|
||||||
).unwrap_or(default.providers),
|
.filter_map(|(name, service)| {
|
||||||
|
match service.to_internal(base_config_dir) {
|
||||||
|
Ok(internal_service) => Some((name, internal_service)),
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("Error loading provider {}: {}. Skipping this provider.", name, err);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<HashMap<String, Providers>>()
|
||||||
|
})
|
||||||
|
.unwrap_or(default.providers),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return default;
|
return default;
|
||||||
@ -83,7 +97,6 @@ impl AppConfig {
|
|||||||
eprintln!("Failed to read config file: {err}. Using default configuration.");
|
eprintln!("Failed to read config file: {err}. Using default configuration.");
|
||||||
return String::new(); // Return empty string to fall back to default
|
return String::new(); // Return empty string to fall back to default
|
||||||
});
|
});
|
||||||
|
|
||||||
let basic_config = AppConfig::from_toml(
|
let basic_config = AppConfig::from_toml(
|
||||||
toml::from_str::<TomlAppConfig>(&contents)
|
toml::from_str::<TomlAppConfig>(&contents)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
|
|||||||
@ -8,13 +8,12 @@ use argon2::{
|
|||||||
use crate::errors::AutoDecryptError;
|
use crate::errors::AutoDecryptError;
|
||||||
use base64::prelude::*;
|
use base64::prelude::*;
|
||||||
use chacha20poly1305::{
|
use chacha20poly1305::{
|
||||||
aead::{Aead, AeadCore, KeyInit, OsRng as AeadOsRng},
|
ChaCha20Poly1305, Nonce, aead::{Aead, AeadCore, KeyInit, OsRng as AeadOsRng}
|
||||||
ChaCha20Poly1305, Nonce
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::app_config::CONFIG;
|
use crate::app_config::CONFIG;
|
||||||
|
|
||||||
fn hash_hey(input: &str) -> Result<(String), AutoDecryptError> {
|
pub(crate) fn hash_hey(input: &str) -> Result<(String), AutoDecryptError> {
|
||||||
let argon2 = Argon2::default();
|
let argon2 = Argon2::default();
|
||||||
let salt = SaltString::generate(&mut OsRng);
|
let salt = SaltString::generate(&mut OsRng);
|
||||||
Ok(argon2.hash_password(input.as_bytes(), &salt).map_err(
|
Ok(argon2.hash_password(input.as_bytes(), &salt).map_err(
|
||||||
@ -22,33 +21,52 @@ fn hash_hey(input: &str) -> Result<(String), AutoDecryptError> {
|
|||||||
.to_string())
|
.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn derive_key(password: &str, salt: &str) -> Result<[u8; 32], AutoDecryptError> {
|
pub(crate) fn derive_key(password: &str, salt: &str) -> Result<[u8; 32], AutoDecryptError> {
|
||||||
let mut output = [0u8; 32];
|
let mut output = [0u8; 32];
|
||||||
Argon2::default().hash_password_into(password.as_bytes(), salt.as_bytes(), &mut output).map_err(
|
Argon2::default().hash_password_into(password.as_bytes(), salt.as_bytes(), &mut output).map_err(
|
||||||
|e| AutoDecryptError::CryptoError { comment: (e.to_string()) })?;
|
|e| AutoDecryptError::CryptoError { comment: (e.to_string()) })?;
|
||||||
Ok(output)
|
Ok(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encrypt_data(data: &str, key: &[u8; 32], salt: Option<[u8; 96]>) -> Result<(String, [u8; 96]), AutoDecryptError> {
|
pub(crate) fn encrypt_data(data: &str, key: &[u8; 32], salt: Option<[u8; 12]>) -> Result<(String, String), AutoDecryptError> {
|
||||||
let cipher = ChaCha20Poly1305::new(key.into());
|
let cipher = ChaCha20Poly1305::new(key.into());
|
||||||
|
|
||||||
let salt = match salt {
|
let salt = match salt {
|
||||||
Some(s) => Nonce::clone_from_slice(&s),
|
Some(s) => Nonce::clone_from_slice(&s),
|
||||||
None => ChaCha20Poly1305::generate_nonce(&mut AeadOsRng),
|
None => ChaCha20Poly1305::generate_nonce(&mut AeadOsRng),
|
||||||
};
|
};
|
||||||
let salt_arr: [u8; 96] = salt.as_slice().try_into().expect("Nonce should be 96 bytes");
|
let salt_arr: [u8; 12] = salt.as_slice().try_into().expect("Nonce should be 12 bytes");
|
||||||
let ciphertext = cipher.encrypt(&salt, data.as_bytes()).map_err(
|
let ciphertext = cipher.encrypt(&salt, data.as_bytes()).map_err(
|
||||||
|e| AutoDecryptError::APIError { comment: (e.to_string()) })?;
|
|e| AutoDecryptError::APIError { comment: (e.to_string()) })?;
|
||||||
Ok((BASE64_STANDARD.encode(ciphertext), salt_arr))
|
Ok((BASE64_STANDARD.encode(ciphertext), BASE64_STANDARD.encode(salt_arr)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decrypt_data(encrypted_data: &str, key: &[u8; 32], salt: &[u8; 96]) -> Result<String, AutoDecryptError> {
|
pub(crate) fn decrypt_data(salt_data: &str, key: &[u8; 32]) -> Result<String, AutoDecryptError> {
|
||||||
let cipher = ChaCha20Poly1305::new(key.into());
|
let cipher = ChaCha20Poly1305::new(key.into());
|
||||||
let nonce = Nonce::from_slice(salt);
|
|
||||||
let ciphertext = BASE64_STANDARD.decode(encrypted_data).map_err(
|
let data = salt_data.split("::").collect::<Vec<&str>>();
|
||||||
|e| AutoDecryptError::APIError { comment: (e.to_string()) })?;
|
let salt_part = read_salt_from_string(data.get(0).ok_or_else(|| AutoDecryptError::ConfigurationError {
|
||||||
let plaintext = cipher.decrypt(nonce, ciphertext.as_ref()).map_err(
|
comment: "Invalid encrypted data format: missing salt".to_string(),
|
||||||
|
})?)?;
|
||||||
|
let encrypted_data = data.get(1).ok_or_else(|| AutoDecryptError::ConfigurationError {
|
||||||
|
comment: "Invalid encrypted data format: missing ciphertext".to_string(),
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let nonce = Nonce::from_slice(&salt_part);
|
||||||
|
|
||||||
|
let cypthertext_bytes = BASE64_STANDARD.decode(encrypted_data).map_err(
|
||||||
|
|e| AutoDecryptError::CryptoError { comment: (e.to_string()) })?;
|
||||||
|
let plaintext = cipher.decrypt(nonce, cypthertext_bytes.as_ref()).map_err(
|
||||||
|e| AutoDecryptError::CryptoError { comment: (e.to_string()) })?;
|
|e| AutoDecryptError::CryptoError { comment: (e.to_string()) })?;
|
||||||
Ok(String::from_utf8(plaintext).map_err(
|
Ok(String::from_utf8(plaintext).map_err(
|
||||||
|e| AutoDecryptError::CryptoError { comment: (e.to_string()) })?)
|
|e| AutoDecryptError::CryptoError { comment: (e.to_string()) })?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn read_salt_from_string(contents: &str) -> Result<[u8; 12], AutoDecryptError> {
|
||||||
|
|
||||||
|
let salt = BASE64_STANDARD.decode(contents).map_err(
|
||||||
|
|e| AutoDecryptError::CryptoError { comment: (e.to_string()) })?;
|
||||||
|
let salt_arr: [u8; 12] = salt.as_slice().try_into().map_err(
|
||||||
|
|_| AutoDecryptError::CryptoError { comment: ("Invalid salt length".to_string()) })?;
|
||||||
|
Ok(salt_arr)
|
||||||
|
}
|
||||||
29
src/main.rs
29
src/main.rs
@ -2,9 +2,18 @@ mod services;
|
|||||||
mod app_config;
|
mod app_config;
|
||||||
mod api;
|
mod api;
|
||||||
mod crypto;
|
mod crypto;
|
||||||
|
use std::process::exit;
|
||||||
|
|
||||||
|
use base64::Engine;
|
||||||
|
use base64::prelude::BASE64_STANDARD;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
use diesel::expression::is_aggregate::No;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
use crate::app_config::{init_config, CONFIG};
|
use crate::app_config::{init_config, CONFIG};
|
||||||
|
use crate::crypto::derive_key;
|
||||||
|
use crate::utils::new_encryption;
|
||||||
|
|
||||||
mod orm;
|
mod orm;
|
||||||
mod errors;
|
mod errors;
|
||||||
|
|
||||||
@ -16,11 +25,29 @@ mod errors;
|
|||||||
struct InputArgs {
|
struct InputArgs {
|
||||||
#[arg(short='c', long, help = "Path to the configuration file", default_value = "debug_config/")]
|
#[arg(short='c', long, help = "Path to the configuration file", default_value = "debug_config/")]
|
||||||
config_file: String,
|
config_file: String,
|
||||||
|
#[arg(long = "get-key", help = "Provideing the passwort, get the key", default_value = None)]
|
||||||
|
get_key: Option<String>,
|
||||||
|
#[arg(long = "provider", help = "Encrypt provider with key", default_value = None)]
|
||||||
|
encrypt_provider: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args = InputArgs::parse();
|
let args = InputArgs::parse();
|
||||||
|
|
||||||
init_config(&args.config_file);
|
init_config(&args.config_file);
|
||||||
|
|
||||||
|
|
||||||
|
if let (Some(key), Some(provider_file)) = (&args.get_key, &args.encrypt_provider){
|
||||||
|
let res = new_encryption(provider_file, key);
|
||||||
|
if res.is_err() {
|
||||||
|
eprintln!("Error encrypting provider file: {}", res.err().unwrap());
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
exit(0)
|
||||||
|
} else if args.get_key.is_some() || args.encrypt_provider.is_some() {
|
||||||
|
eprintln!("Both --get-key and --provider must be provided together.");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
api::start_api();
|
api::start_api();
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -21,16 +21,18 @@ impl DbConn {
|
|||||||
.expect("Error saving new service record");
|
.expect("Error saving new service record");
|
||||||
}
|
}
|
||||||
pub(crate) fn update_provider_state(&self, id: i32, new_state: RecordStates) -> ProviderRecord {
|
pub(crate) fn update_provider_state(&self, id: i32, new_state: RecordStates) -> ProviderRecord {
|
||||||
let conn = &mut *self.0.lock().unwrap();
|
{
|
||||||
let now_unix = SystemTime::now()
|
let conn = &mut *self.0.lock().unwrap();
|
||||||
.duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs() as i64;
|
let now_unix = SystemTime::now()
|
||||||
diesel::update(providers_records::table.filter(providers_records::dsl::id.eq(id)))
|
.duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs() as i64;
|
||||||
.set((
|
diesel::update(providers_records::table.filter(providers_records::dsl::id.eq(id)))
|
||||||
providers_records::state.eq(new_state.to_string()),
|
.set((
|
||||||
providers_records::awnsered_at.eq(Some(now_unix)),
|
providers_records::state.eq(new_state.to_string()),
|
||||||
))
|
providers_records::awnsered_at.eq(Some(now_unix)),
|
||||||
.execute(conn)
|
))
|
||||||
.expect("Error updating service record state");
|
.execute(conn)
|
||||||
|
.expect("Error updating service record state");
|
||||||
|
}
|
||||||
self.get_record(id).unwrap()
|
self.get_record(id).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
use diesel::sqlite::SqliteConnection;
|
use diesel::sqlite::SqliteConnection;
|
||||||
use diesel::Connection;
|
use diesel::Connection;
|
||||||
|
use std::path::Path;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
mod schema;
|
mod schema;
|
||||||
|
|||||||
@ -25,7 +25,4 @@ diesel::table! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::allow_tables_to_appear_in_same_query!(
|
diesel::allow_tables_to_appear_in_same_query!(beggars_records, providers_records,);
|
||||||
beggars_records,
|
|
||||||
providers_records,
|
|
||||||
);
|
|
||||||
|
|||||||
@ -2,7 +2,10 @@ use std::f32::consts::E;
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use async_ssh2_tokio::Config;
|
use async_ssh2_tokio::Config;
|
||||||
|
use base64::Engine;
|
||||||
|
use log::info;
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
|
use base64::prelude::BASE64_STANDARD;
|
||||||
use reqwest::header::{HeaderName, HeaderValue};
|
use reqwest::header::{HeaderName, HeaderValue};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use async_ssh2_tokio::client::{self, AuthMethod, Client as SSHClient, ServerCheckMethod};
|
use async_ssh2_tokio::client::{self, AuthMethod, Client as SSHClient, ServerCheckMethod};
|
||||||
@ -10,8 +13,10 @@ use rocket::futures::TryFutureExt;
|
|||||||
use rocket::tokio::fs;
|
use rocket::tokio::fs;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use enum_dispatch::enum_dispatch;
|
use enum_dispatch::enum_dispatch;
|
||||||
|
use toml::value::Array;
|
||||||
|
|
||||||
use crate::app_config::CONFIG;
|
use crate::app_config::CONFIG;
|
||||||
|
use crate::crypto::derive_key;
|
||||||
use crate::errors::AutoDecryptError;
|
use crate::errors::AutoDecryptError;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
@ -113,14 +118,26 @@ impl ProviderAction for ForigneAction {}
|
|||||||
impl ForigneAction {
|
impl ForigneAction {
|
||||||
pub(crate) fn load_from_file(&mut self, find_in_dir: &Path) -> Result<&mut Self, AutoDecryptError> {
|
pub(crate) fn load_from_file(&mut self, find_in_dir: &Path) -> Result<&mut Self, AutoDecryptError> {
|
||||||
let content = std::fs::read_to_string(find_in_dir.join(&self.filename))
|
let content = std::fs::read_to_string(find_in_dir.join(&self.filename))
|
||||||
.map_err(|err| AutoDecryptError::ConfigurationError { comment: err.to_string() })?;
|
.map_err(|err| AutoDecryptError::ConfigurationError { comment: format!("{}: {}", self.filename, err.to_string() ) })?;
|
||||||
self.content = Some(content);
|
self.content = Some(content);
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub(crate) fn to_executable_action(&self, key: Option<&str>) -> Result<ActionType, AutoDecryptError> {
|
pub(crate) fn to_executable_action(&self, key: Option<&str>) -> Result<ActionType, AutoDecryptError> {
|
||||||
todo!()
|
let content = std::fs::read_to_string(Path::new(&CONFIG.wait().base_config_dir).join(&self.filename))
|
||||||
|
.map_err(|err| AutoDecryptError::ConfigurationError { comment: format!("{}: {}", self.filename, err.to_string() ) })?.trim().to_string();
|
||||||
|
let cleartext_toml = if self.is_encrypted {
|
||||||
|
let derived_key = derive_key(key.unwrap(), &CONFIG.wait().crypto_key)?;
|
||||||
|
crate::crypto::decrypt_data(&content, &derived_key)?
|
||||||
|
} else {
|
||||||
|
content
|
||||||
|
};
|
||||||
|
|
||||||
|
let action: ActionType = toml::from_str(&cleartext_toml)
|
||||||
|
.map_err(|err| AutoDecryptError::ConfigurationError { comment: format!("Failed to parse action TOML: {}", err.to_string()) })?;
|
||||||
|
return Ok(action);
|
||||||
|
|
||||||
//let cleartext_toml =
|
//let cleartext_toml =
|
||||||
//1. get Cleartext toml 2. load tomel as any other 3. return object
|
//1. get Cleartext toml 2. load tomel as any other 3. return object
|
||||||
}
|
}
|
||||||
|
|||||||
22
src/utils.rs
Normal file
22
src/utils.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
use crate::CONFIG;
|
||||||
|
use crate::crypto;
|
||||||
|
use base64::Engine;
|
||||||
|
use base64::prelude::BASE64_STANDARD;
|
||||||
|
|
||||||
|
pub(crate) fn new_encryption(file: &str, key: &str) -> Result<String, String> {
|
||||||
|
let derived_key = crypto::derive_key(key, &CONFIG.wait().crypto_key).unwrap();
|
||||||
|
let hashed_key = crypto::hash_hey(key).unwrap();
|
||||||
|
|
||||||
|
let unencrypted_file = std::fs::read_to_string(file).map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
|
let (encrypted_data, salt) = crypto::encrypt_data(&unencrypted_file, &derived_key, None).map_err(|e| e.to_string())?;
|
||||||
|
// We store the salt at the start of the file, base64 encoded
|
||||||
|
let file_content = format!("{}::{}\n", salt, encrypted_data);
|
||||||
|
|
||||||
|
let encrypted_file = format!("{}.enc", file);
|
||||||
|
std::fs::write(&encrypted_file, file_content).map_err(|e| e.to_string())?;
|
||||||
|
println!("File encrypted and saved to {}", encrypted_file);
|
||||||
|
println!("Key hash (store this to decrypt later): {}", hashed_key);
|
||||||
|
|
||||||
|
Ok(hashed_key)
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user