refactored configuration, implemented basic request
This commit is contained in:
parent
8ee4fe14ff
commit
22a6c8818b
45
.vscode/launch.json
vendored
Normal file
45
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug executable 'auto-decrypt'",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"build",
|
||||
"--bin=auto-decrypt",
|
||||
"--package=auto-decrypt"
|
||||
],
|
||||
"filter": {
|
||||
"name": "auto-decrypt",
|
||||
"kind": "bin"
|
||||
}
|
||||
},
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug unit tests in executable 'auto-decrypt'",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"test",
|
||||
"--no-run",
|
||||
"--bin=auto-decrypt",
|
||||
"--package=auto-decrypt"
|
||||
],
|
||||
"filter": {
|
||||
"name": "auto-decrypt",
|
||||
"kind": "bin"
|
||||
}
|
||||
},
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
}
|
||||
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -227,6 +227,7 @@ dependencies = [
|
||||
"clap",
|
||||
"custom_error",
|
||||
"diesel",
|
||||
"enum_dispatch",
|
||||
"log",
|
||||
"reqwest",
|
||||
"rocket",
|
||||
|
||||
@ -14,4 +14,5 @@ log = "0.4.27"
|
||||
diesel = { version = "2.2.0", features = ["sqlite", "returning_clauses_for_sqlite_3_35"] }
|
||||
rocket = "0.5.1"
|
||||
url = "2"
|
||||
custom_error = "1.9.2"
|
||||
custom_error = "1.9.2"
|
||||
enum_dispatch = "0.3.13"
|
||||
@ -10,10 +10,12 @@ let
|
||||
in
|
||||
nixpkgs.mkShell {
|
||||
buildInputs = [
|
||||
(nixpkgs.rustChannelOf {
|
||||
((nixpkgs.rustChannelOf {
|
||||
channel = "stable";
|
||||
date = null; # null means latest
|
||||
}).rust
|
||||
}).rust.override {
|
||||
extensions = [ "rust-src" "rust-analysis" ];
|
||||
})
|
||||
nixpkgs.openssl
|
||||
nixpkgs.pkg-config
|
||||
nixpkgs.sqlite
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
use clap::Error;
|
||||
use rocket::form::Strict;
|
||||
use rocket::request::{Outcome, Request, FromRequest};
|
||||
use url::form_urlencoded;
|
||||
@ -7,10 +8,7 @@ use crate::api::State;
|
||||
use rocket::http::uri::Query;
|
||||
|
||||
use crate::services::providers::Providers;
|
||||
|
||||
pub(super) struct APIProviderRequest<'r> {
|
||||
pub share: &'r Providers,
|
||||
}
|
||||
use super::HttpResult;
|
||||
|
||||
|
||||
fn get_query_value(query: &Option<Query>, query_key: &str) -> Option<String> {
|
||||
@ -25,36 +23,38 @@ fn get_query_value(query: &Option<Query>, query_key: &str) -> Option<String> {
|
||||
None
|
||||
}
|
||||
|
||||
|
||||
pub(super) struct APIProviderRequest<'r> {
|
||||
pub share: &'r Providers,
|
||||
}
|
||||
|
||||
#[rocket::async_trait]
|
||||
impl<'r> FromRequest<'r> for APIProviderRequest<'r> {
|
||||
type Error = ();
|
||||
type Error = HttpResult;
|
||||
|
||||
async fn from_request(req: &'r Request<'_>) -> Outcome<Self, Self::Error> {
|
||||
//let db_conn = req.guard::<&State<DbConn>>().await.unwrap();
|
||||
let path = req
|
||||
.uri()
|
||||
.path()
|
||||
.segments();
|
||||
let path = req.uri().path().segments();
|
||||
let share_name: &str = path.get(path.len() - 1).unwrap_or(&"");
|
||||
|
||||
let access_key: &str = &get_query_value(&req.uri().query(), "trigger_key").unwrap_or("".to_string());
|
||||
if share_name == "" {
|
||||
Outcome::Error((rocket::http::Status::BadRequest, ()))
|
||||
} else {
|
||||
let share: Option<&Providers> = CONFIG.wait().providers.iter()
|
||||
.find(|service| service.name == share_name)
|
||||
.and_then(|service| {
|
||||
if service.access_key == access_key {
|
||||
Some(service)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
if share.is_none() {
|
||||
return Outcome::Error((rocket::http::Status::NotFound, ()))
|
||||
}
|
||||
let access_key: &str = &get_query_value(&req.uri().query(), "trigger_key")
|
||||
.unwrap_or_default();
|
||||
|
||||
return Outcome::Success(APIProviderRequest { share: share.unwrap() })
|
||||
if share_name.is_empty() {
|
||||
return Outcome::Error(HttpResult::ShareNotFound("No share name provided.".to_string()).into());
|
||||
}
|
||||
|
||||
if let Some(service) = CONFIG
|
||||
.wait()
|
||||
.providers
|
||||
.iter()
|
||||
.find(|(name, service)| *name == share_name && service.access_key_hash == access_key)
|
||||
{
|
||||
Outcome::Success(APIProviderRequest { share: service.1 })
|
||||
} else {
|
||||
Outcome::Error(HttpResult::ShareNotFound(format!(
|
||||
"Share '{}' not found.",
|
||||
share_name
|
||||
)).into())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4,21 +4,68 @@ mod request;
|
||||
use crate::app_config::CONFIG;
|
||||
use crate::orm::DbConn;
|
||||
// Alternativly iport rocket manually: use rocket::get;
|
||||
use rocket::fs::FileServer;
|
||||
use rocket::{fs::FileServer, Config};
|
||||
use rocket::response::Redirect;
|
||||
use rocket::fs::NamedFile;
|
||||
use rocket::State;
|
||||
use serde::Deserialize;
|
||||
use core::marker::{Send, Sync};
|
||||
use std::net::IpAddr;
|
||||
use rocket::http::Status;
|
||||
use rocket::Request;
|
||||
|
||||
|
||||
|
||||
#[derive(Responder, Debug)]
|
||||
pub(super) enum HttpResult {
|
||||
UnlockingSucceeded(String),
|
||||
AckAuthReq(String),
|
||||
AuthFailiure(String),
|
||||
ShareNotFound(String),
|
||||
TimelimitExceeded(String),
|
||||
TooManyRequests(String),
|
||||
UnlockingFailed(String),
|
||||
}
|
||||
|
||||
impl Into<(Status, HttpResult)> for HttpResult {
|
||||
fn into(self) -> (Status, HttpResult) {
|
||||
let status = match &self {
|
||||
HttpResult::UnlockingSucceeded(_) => Status::Ok,
|
||||
HttpResult::AckAuthReq(_) => Status::Accepted,
|
||||
HttpResult::AuthFailiure(_) => Status::Unauthorized,
|
||||
HttpResult::ShareNotFound(_) => Status::NotFound,
|
||||
HttpResult::TimelimitExceeded(_) => Status::RequestTimeout,
|
||||
HttpResult::TooManyRequests(_) => Status::TooManyRequests,
|
||||
HttpResult::UnlockingFailed(_) => Status::InternalServerError,
|
||||
};
|
||||
(status, self)
|
||||
}
|
||||
}
|
||||
|
||||
#[get("/", rank = 1)]
|
||||
async fn index() -> String {
|
||||
"Welcome to the Auto-Decrypt API!".to_string()
|
||||
"Auto-Decrypt API! DEV!".to_string()
|
||||
}
|
||||
|
||||
|
||||
#[catch(default)]
|
||||
fn default(_status: Status, req: &Request) -> String {
|
||||
format!("{:?}", req)
|
||||
}
|
||||
|
||||
|
||||
#[rocket::main]
|
||||
pub(crate) async fn start_api() -> () {
|
||||
let rocket_config = Config{
|
||||
port: CONFIG.wait().port,
|
||||
..Default::default()};
|
||||
|
||||
let _ = rocket::build()
|
||||
.manage(DbConn::establish_connection(&CONFIG.wait().db_file)) // Manage the state here
|
||||
.manage(DbConn::establish_connection(&CONFIG.wait().db_file))
|
||||
.mount("/", routes![index])
|
||||
.register("/", catchers![default])
|
||||
.mount("/request", routes![request::request_handler])
|
||||
.configure(rocket_config)
|
||||
.launch()
|
||||
.await;
|
||||
}
|
||||
@ -1,25 +1,43 @@
|
||||
|
||||
use super::guards::APIProviderRequest;
|
||||
use crate::services::providers::ConsentMethode;
|
||||
use crate::api::guards;
|
||||
use crate::services::providers::{ConsentMethode, ProviderAction, Providers};
|
||||
use crate::app_config::CONFIG;
|
||||
use rocket::get;
|
||||
use rocket::http::Status;
|
||||
use super::HttpResult;
|
||||
|
||||
|
||||
async fn execute_action(action: &Providers) -> Result<String, String> {
|
||||
let action: &dyn ProviderAction = &action.execution_action;
|
||||
action.execute().await
|
||||
}
|
||||
|
||||
#[get("/<_>", rank = 1)]
|
||||
async fn request_handler(guard: APIProviderRequest<'_>) -> String {
|
||||
pub(super) async fn request_handler(guard: Result<APIProviderRequest<'_>, HttpResult>) -> (Status, HttpResult) {
|
||||
// We assume the request guard verified th access_key against the service_name
|
||||
if let Err(err) = guard {
|
||||
// This wrapper is nessesary to avoid needing to write catchers, and recompute the error
|
||||
// See: https://github.com/rwf2/Rocket/issues/749
|
||||
return err.into();
|
||||
}
|
||||
let guard = guard.expect("A rejected request guard was able to perseed!");
|
||||
|
||||
match guard.share.consent_methode {
|
||||
let result: HttpResult = match guard.share.consent_methode {
|
||||
ConsentMethode::None => {
|
||||
// We do not wait for constent, direct feedback is impleied
|
||||
todo!()
|
||||
match execute_action(guard.share).await {
|
||||
Ok(response) => HttpResult::UnlockingSucceeded(response),
|
||||
Err(err) => HttpResult::UnlockingFailed(err),
|
||||
}
|
||||
},
|
||||
ConsentMethode::Boolean => {
|
||||
todo!()
|
||||
},
|
||||
ConsentMethode::Passkey(_) => {
|
||||
ConsentMethode::PassheyHash(_) => {
|
||||
todo!()
|
||||
},
|
||||
}
|
||||
|
||||
};
|
||||
return result.into();
|
||||
|
||||
}
|
||||
@ -1,115 +0,0 @@
|
||||
use std::sync::OnceLock;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use serde::{ser, Deserialize};
|
||||
|
||||
use crate::services::beggars::Beggars;
|
||||
use crate::services::providers::Providers;
|
||||
use crate::errors::AutoDecryptError;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
enum Platform {
|
||||
OMV,
|
||||
TrueNas,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub(crate) struct AppConfig {
|
||||
pub(crate) port: u16,
|
||||
pub(crate) addresses: Vec<String>,
|
||||
pub(crate) platform: Platform,
|
||||
pub(crate) ssh_known_host_file: String,
|
||||
|
||||
pub(crate) db_file: String,
|
||||
|
||||
pub(crate) beggars: Vec<Beggars>, // We request to unlock owned services
|
||||
pub(crate) providers: Vec<Providers>, // We offer to unlock these services
|
||||
}
|
||||
|
||||
impl Default for AppConfig {
|
||||
fn default() -> Self {
|
||||
AppConfig {
|
||||
port: 8080,
|
||||
addresses: vec!["*".to_string()],
|
||||
beggars: vec![],
|
||||
providers: vec![],
|
||||
platform: Platform::OMV,
|
||||
ssh_known_host_file: "".to_string(),
|
||||
db_file: "/var/auto-decrypt/db.sqlite".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AppConfig {
|
||||
|
||||
fn load_provided_services(at_path: &Path) -> Result<Vec<Providers>, AutoDecryptError> {
|
||||
let mut provided_services = vec![];
|
||||
if let Ok(entries) = fs::read_dir(at_path) {
|
||||
for entry in entries {
|
||||
let entry = entry.map_err(|e| AutoDecryptError::ConfigurationErroro { comment: e.to_string() })?;
|
||||
if entry.path().extension().and_then(|s| s.to_str()) == Some("toml") {
|
||||
let service: Providers = toml::from_str(&fs::read_to_string(entry.path()).map_err(|e| AutoDecryptError::ConfigurationErroro { comment: e.to_string() })?)
|
||||
.map_err(|e| AutoDecryptError::ConfigurationErroro { comment: e.to_string() })?;
|
||||
provided_services.push(service);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(provided_services)
|
||||
}
|
||||
|
||||
fn load_requesting_services(at_path: &Path) -> Result<Vec<Beggars>, AutoDecryptError> {
|
||||
let mut requesting_services = vec![];
|
||||
if let Ok(entries) = fs::read_dir(at_path) {
|
||||
for entry in entries {
|
||||
let entry = entry.map_err(|e| AutoDecryptError::ConfigurationErroro { comment: e.to_string() })?;
|
||||
if entry.path().extension().and_then(|s| s.to_str()) == Some("toml") {
|
||||
let service: Beggars = toml::from_str(&fs::read_to_string(entry.path()).map_err(|e| AutoDecryptError::ConfigurationErroro { comment: e.to_string() })?)
|
||||
.map_err(|e| AutoDecryptError::ConfigurationErroro { comment: e.to_string() })?;
|
||||
requesting_services.push(service);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(requesting_services)
|
||||
}
|
||||
|
||||
pub fn load_from_file(path: &Path ) -> Result<Self, AutoDecryptError> {
|
||||
if !path.is_dir(){
|
||||
return Err(AutoDecryptError::ConfigurationErroro { comment: ("The provided configuration path is not a Folder!".to_string()) })
|
||||
}
|
||||
|
||||
let contents = fs::read_to_string(path.join("config.toml"))
|
||||
.unwrap_or_else(|err| {
|
||||
eprintln!("Failed to read config file: {err}. Using default configuration.");
|
||||
return String::new(); // Return empty string to fall back to default
|
||||
});
|
||||
|
||||
let mut basic_config = toml::from_str(&contents)
|
||||
.unwrap_or_else(|err| {
|
||||
eprintln!("Failed to parse config file: {err}. Using default configuration.");
|
||||
Self::default()
|
||||
});
|
||||
|
||||
|
||||
basic_config.beggars = Self::load_requesting_services(&path.join("requesting_services"))
|
||||
.unwrap_or_else(|err| {
|
||||
eprintln!("Failed to load requesting services: {err}. Using empty list.");
|
||||
vec![]
|
||||
});
|
||||
|
||||
basic_config.providers = Self::load_provided_services(&path.join("provided_services"))
|
||||
.unwrap_or_else(|err| {
|
||||
eprintln!("Failed to load provided services: {err}. Using empty list.");
|
||||
vec![]
|
||||
});
|
||||
|
||||
return Ok(basic_config);
|
||||
}
|
||||
}
|
||||
|
||||
pub static CONFIG: OnceLock<AppConfig> = OnceLock::new();
|
||||
|
||||
pub fn init_config(file: &str) {
|
||||
let config = AppConfig::load_from_file(Path::new(file))
|
||||
.expect("Failed to load configuration file");
|
||||
CONFIG.set(config).expect("AppConfig can only be initialized once");
|
||||
}
|
||||
20
src/app_config/general_config.rs
Normal file
20
src/app_config/general_config.rs
Normal file
@ -0,0 +1,20 @@
|
||||
use serde::Deserialize;
|
||||
use std::collections::HashMap;
|
||||
use crate::{app_config::providers::TomlProviders, services::beggars::Beggars};
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub (super) struct TomlAppConfig {
|
||||
pub (super) port: Option<u16>,
|
||||
pub (super) addresses: Option<Vec<String>>,
|
||||
pub (super) platform: Option<Platform>,
|
||||
pub (super) ssh_known_host_file: Option<String>,
|
||||
pub (super) db_file: Option<String>,
|
||||
pub (super) beggars: Option<HashMap<String, Beggars>>,
|
||||
pub (super) providers: Option<HashMap<String, TomlProviders>>
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub(crate) enum Platform {
|
||||
OMV,
|
||||
TrueNas,
|
||||
}
|
||||
100
src/app_config/mod.rs
Normal file
100
src/app_config/mod.rs
Normal file
@ -0,0 +1,100 @@
|
||||
mod general_config;
|
||||
mod providers;
|
||||
|
||||
use std::hash::Hash;
|
||||
use std::{collections::HashMap, sync::OnceLock};
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use clap::builder::Str;
|
||||
use serde::{ser, Deserialize};
|
||||
|
||||
use crate::services::beggars::Beggars;
|
||||
use crate::services::providers::Providers;
|
||||
use crate::errors::AutoDecryptError;
|
||||
|
||||
use general_config::{Platform, TomlAppConfig};
|
||||
|
||||
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub(crate) struct AppConfig {
|
||||
pub(crate) port: u16,
|
||||
pub(crate) addresses: Vec<String>,
|
||||
pub(crate) platform: Platform,
|
||||
pub(crate) ssh_known_host_file: String,
|
||||
|
||||
pub(crate) db_file: String,
|
||||
|
||||
pub(crate) beggars: HashMap<String, Beggars>, // We request to unlock owned services
|
||||
pub(crate) providers: HashMap<String, Providers>, // We offer to unlock these services
|
||||
}
|
||||
|
||||
impl Default for AppConfig {
|
||||
fn default() -> Self {
|
||||
AppConfig {
|
||||
port: 8080,
|
||||
addresses: vec!["*".to_string()],
|
||||
beggars: HashMap::new(),
|
||||
providers: HashMap::new(),
|
||||
platform: Platform::OMV,
|
||||
ssh_known_host_file: "".to_string(),
|
||||
db_file: "/var/auto-decrypt/db.sqlite".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AppConfig {
|
||||
fn from_toml(toml_config: Option<TomlAppConfig>, base_config_dir: &Path) -> Self {
|
||||
let default = AppConfig::default();
|
||||
if let Some(toml_config) = toml_config {
|
||||
return AppConfig {
|
||||
port: toml_config.port.unwrap_or(default.port),
|
||||
addresses: toml_config.addresses.unwrap_or(default.addresses),
|
||||
platform: toml_config.platform.unwrap_or(default.platform),
|
||||
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),
|
||||
beggars: toml_config.beggars.unwrap_or(default.beggars),
|
||||
providers: toml_config.providers.and_then(|providers|
|
||||
Some(providers.into_iter().map(|(name, service)|
|
||||
(name, service.to_internal(base_config_dir).expect("Err"))
|
||||
).collect::<HashMap<String, Providers>>())
|
||||
).unwrap_or(default.providers),
|
||||
};
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl AppConfig {
|
||||
|
||||
pub fn load_from_file(path: &Path ) -> Result<Self, AutoDecryptError> {
|
||||
if !path.is_dir(){
|
||||
return Err(AutoDecryptError::ConfigurationError { comment: ("The provided configuration path is not a Folder!".to_string()) })
|
||||
}
|
||||
|
||||
let contents = fs::read_to_string(path.join("config.toml"))
|
||||
.unwrap_or_else(|err| {
|
||||
eprintln!("Failed to read config file: {err}. Using default configuration.");
|
||||
return String::new(); // Return empty string to fall back to default
|
||||
});
|
||||
|
||||
let basic_config = AppConfig::from_toml(
|
||||
toml::from_str::<TomlAppConfig>(&contents)
|
||||
.map_err(|err| {
|
||||
eprintln!("Failed to parse config file: {err}. Using default configuration.");
|
||||
err
|
||||
})
|
||||
.ok()
|
||||
, path);
|
||||
return Ok(basic_config);
|
||||
}
|
||||
}
|
||||
|
||||
pub static CONFIG: OnceLock<AppConfig> = OnceLock::new();
|
||||
|
||||
pub fn init_config(file: &str) {
|
||||
let config = AppConfig::load_from_file(Path::new(file))
|
||||
.expect("Failed to load configuration file");
|
||||
CONFIG.set(config).expect("AppConfig can only be initialized once");
|
||||
}
|
||||
32
src/app_config/providers.rs
Normal file
32
src/app_config/providers.rs
Normal file
@ -0,0 +1,32 @@
|
||||
use std::path::Path;
|
||||
|
||||
use serde::Deserialize;
|
||||
use crate::errors::AutoDecryptError;
|
||||
use crate::services::providers::ConsentMethode;
|
||||
use crate::services::providers::ActionType;
|
||||
use crate::services::providers::Providers;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub (super) struct TomlProviders {
|
||||
pub(crate) access_key_hash: Option<String>,
|
||||
pub(crate) execution_action: ActionType,
|
||||
pub(crate) consent_methode: Option<ConsentMethode>,
|
||||
}
|
||||
|
||||
|
||||
|
||||
impl TomlProviders {
|
||||
pub(super) fn to_internal(mut self, base_config_dir: &Path) -> Result<Providers, AutoDecryptError> {
|
||||
if let ActionType::EncryptedRequest(ref mut action_type) = self.execution_action {
|
||||
if action_type.content.is_none() {
|
||||
action_type.load_from_file(base_config_dir)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Providers {
|
||||
access_key_hash: self.access_key_hash.unwrap_or("".to_string()),
|
||||
consent_methode: self.consent_methode.unwrap_or(ConsentMethode::None),
|
||||
execution_action: self.execution_action,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
use custom_error::custom_error;
|
||||
|
||||
custom_error!{pub AutoDecryptError
|
||||
ConfigurationErroro{comment:String} = "{comment}",
|
||||
ConfigurationError{comment:String} = "{comment}",
|
||||
APIError{comment:String} = "{comment}",
|
||||
ORMError{comment:String} = "{comment}",
|
||||
}
|
||||
@ -1,35 +1,46 @@
|
||||
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,
|
||||
Passkey(String),
|
||||
PassheyHash(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[enum_dispatch(ProviderAction)]
|
||||
pub(crate) enum ActionType {
|
||||
HTTPRequest(HTTPRequest),
|
||||
SSHRequest(SSHRequest),
|
||||
HTTPRequest(HTTPAction),
|
||||
SSHRequest(SSHAction),
|
||||
EncryptedRequest(EncryptedAction)
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Providers {
|
||||
pub(crate) name: String,
|
||||
pub(crate) access_key: String,
|
||||
pub(crate) access_key_hash: String,
|
||||
pub(crate) consent_methode: ConsentMethode,
|
||||
pub(crate) execution_action: ActionType,
|
||||
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 HTTPRequest {
|
||||
struct HTTPAction {
|
||||
pub(crate) method: String,
|
||||
pub(crate) uri: String,
|
||||
pub(crate) headers: Option<Vec<(String, String)>>,
|
||||
@ -37,7 +48,7 @@ struct HTTPRequest {
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl ServiceAction for HTTPRequest {
|
||||
impl ProviderAction for HTTPAction {
|
||||
async fn execute(&self) -> Result<String, String> {
|
||||
let client = Client::new();
|
||||
let mut req_builder = client.request(
|
||||
@ -55,12 +66,12 @@ impl ServiceAction for HTTPRequest {
|
||||
}
|
||||
let response = req_builder.send().await
|
||||
.map_err(|e| e.to_string())?;
|
||||
response.text().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 SSHRequest {
|
||||
struct SSHAction {
|
||||
pub(crate) uri: String,
|
||||
pub(crate) port: u16,
|
||||
pub(crate) username: String,
|
||||
@ -69,7 +80,7 @@ struct SSHRequest {
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl ServiceAction for SSHRequest {
|
||||
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(
|
||||
@ -88,7 +99,35 @@ impl ServiceAction for SSHRequest {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
trait ServiceAction: std::fmt::Debug + Send + Sync {
|
||||
async fn execute(&self) -> Result<String, String>;
|
||||
#[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())
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user