auto-decrypt/src/services/providers.rs

134 lines
4.0 KiB
Rust

use std::path::Path;
use async_ssh2_tokio::Config;
use reqwest::Client;
use reqwest::header::{HeaderName, HeaderValue};
use async_trait::async_trait;
use async_ssh2_tokio::client::{self, AuthMethod, Client as SSHClient, ServerCheckMethod};
use rocket::futures::TryFutureExt;
use rocket::tokio::fs;
use serde::Deserialize;
use enum_dispatch::enum_dispatch;
use crate::app_config::CONFIG;
use crate::errors::AutoDecryptError;
#[derive(Debug, Deserialize)]
pub(crate) enum ConsentMethode {
None,
Boolean,
PassheyHash(String),
}
#[derive(Debug, Deserialize)]
#[enum_dispatch(ProviderAction)]
pub(crate) enum ActionType {
HTTPRequest(HTTPAction),
SSHRequest(SSHAction),
EncryptedRequest(EncryptedAction)
}
#[derive(Debug, Deserialize)]
pub struct Providers {
pub(crate) access_key_hash: String,
pub(crate) consent_methode: ConsentMethode,
pub(crate) execution_action: ActionType,
// if action in seperate file and constent methode is passkey, we try
// to decrypt the action file with the passkey
}
#[derive(Debug, Deserialize)]
struct HTTPAction {
pub(crate) method: String,
pub(crate) uri: String,
pub(crate) headers: Option<Vec<(String, String)>>,
pub(crate) body: Option<String>,
}
#[async_trait]
impl ProviderAction for HTTPAction {
async fn execute(&self) -> Result<String, String> {
let client = Client::new();
let mut req_builder = client.request(
reqwest::Method::from_bytes(self.method.as_bytes())
.map_err(|e| e.to_string())?,
&self.uri,
);
if let Some(headers) = &self.headers {
for (key, value) in headers {
req_builder = req_builder.header(
HeaderName::from_bytes(key.as_bytes()).map_err(|e| e.to_string())?,
HeaderValue::from_str(value).map_err(|e| e.to_string())?,
);
}
}
let response = req_builder.send().await
.map_err(|e| e.to_string())?;
Ok(format!("Success! Server replied with: {}", response.text().await.map_err(|e| e.to_string())?))
}
}
#[derive(Debug, Deserialize)]
struct SSHAction {
pub(crate) uri: String,
pub(crate) port: u16,
pub(crate) username: String,
pub(crate) private_key: String,
pub(crate) cmd: String,
}
#[async_trait]
impl ProviderAction for SSHAction {
async fn execute(&self) -> Result<String, String> {
let auth_method = AuthMethod::PrivateKey { key_data: self.private_key.clone(), key_pass: None };
let client = SSHClient::connect(
(&*self.uri, self.port),
&self.username,
auth_method,
ServerCheckMethod::KnownHostsFile(CONFIG.wait().ssh_known_host_file.clone()),
).await.map_err(|e| e.to_string())?;
let result = client.execute(&self.cmd).await.map_err(|e| e.to_string())?;
if result.exit_status == 0 {
Ok(result.stdout)
} else {
Err(result.stderr)
}
}
}
#[derive(Debug, Deserialize)]
pub struct EncryptedAction{
pub(crate) filename: String,
pub(crate) content: Option<String>
}
impl ProviderAction for EncryptedAction {}
impl EncryptedAction {
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))
.map_err(|err| AutoDecryptError::ConfigurationError { comment: err.to_string() })?;
self.content = Some(content);
Ok(self)
}
async fn to_executable_action(&self, key: &str) -> Result<ActionType, AutoDecryptError> {
todo!()
//let cleartext_toml =
//1. get Cleartext toml 2. load tomel as any other 3. return object
}
}
#[async_trait]
#[enum_dispatch]
pub (crate) trait ProviderAction: std::fmt::Debug + Send + Sync {
async fn execute(&self) -> Result<String, String> {
return Err("We are not directly executable!".to_string())
}
}