implemented requsting unlock request
This commit is contained in:
parent
22a6c8818b
commit
230943ba64
6
.vscode/extensions.json
vendored
Normal file
6
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"vadimcn.vscode-lldb",
|
||||
"rust-lang.rust-analyzer"
|
||||
]
|
||||
}
|
||||
@ -1,2 +1,3 @@
|
||||
-- This file should undo anything in `up.sql`
|
||||
DROP TABLE IF EXISTS sessions;
|
||||
DROP TABLE IF EXISTS providers_records;
|
||||
DROP TABLE IF EXISTS providers_records;
|
||||
@ -1,10 +1,20 @@
|
||||
-- Your SQL goes here
|
||||
CREATE TABLE sessions (
|
||||
CREATE TABLE providers_records (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
service_name TEXT NOT NULL,
|
||||
request_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
expires_at TIMESTAMP,
|
||||
request_time BIGINT UNSIGNED NOT NULL,
|
||||
auth_methode TEXT NOT NULL,
|
||||
expires_at BIGINT UNSIGNED,
|
||||
state TEXT NOT NULL,
|
||||
awnsered_at TIMESTAMP,
|
||||
awnsered_at BIGINT UNSIGNED,
|
||||
awnsered_by TEXT
|
||||
)
|
||||
);
|
||||
|
||||
CREATE TABLE beggars_records (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
request_time BIGINT UNSIGNED NOT NULL,
|
||||
service_name TEXT NOT NULL,
|
||||
http_result INTEGER UNSIGNED NOT NULL,
|
||||
note TEXT,
|
||||
awnsered_by TEXT
|
||||
);
|
||||
@ -1,3 +0,0 @@
|
||||
-- This file should undo anything in `up.sql`
|
||||
DROP TABLE beggars_records;
|
||||
ALTER TABLE providers_records RENAME TO sessions;
|
||||
@ -1,10 +0,0 @@
|
||||
-- Your SQL goes here
|
||||
CREATE TABLE beggars_records (
|
||||
request_time TIMESTAMP PRIMARY KEY DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
service_name TEXT NOT NULL,
|
||||
http_result INTEGER NOT NULL,
|
||||
note TEXT,
|
||||
awnsered_by TEXT
|
||||
);
|
||||
|
||||
ALTER TABLE sessions RENAME TO providers_records;
|
||||
@ -26,6 +26,7 @@ fn get_query_value(query: &Option<Query>, query_key: &str) -> Option<String> {
|
||||
|
||||
pub(super) struct APIProviderRequest<'r> {
|
||||
pub share: &'r Providers,
|
||||
pub name: &'r str,
|
||||
}
|
||||
|
||||
#[rocket::async_trait]
|
||||
@ -49,7 +50,7 @@ impl<'r> FromRequest<'r> for APIProviderRequest<'r> {
|
||||
.iter()
|
||||
.find(|(name, service)| *name == share_name && service.access_key_hash == access_key)
|
||||
{
|
||||
Outcome::Success(APIProviderRequest { share: service.1 })
|
||||
Outcome::Success(APIProviderRequest { share: service.1, name: service.0 })
|
||||
} else {
|
||||
Outcome::Error(HttpResult::ShareNotFound(format!(
|
||||
"Share '{}' not found.",
|
||||
|
||||
5
src/api/notifier.rs
Normal file
5
src/api/notifier.rs
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
|
||||
pub fn send_user_notification(record: ProviderRecord) -> Result<(), AutoDecryptError> {
|
||||
todo!("Implement user notification logic here");
|
||||
}
|
||||
@ -1,20 +1,34 @@
|
||||
|
||||
use super::guards::APIProviderRequest;
|
||||
use crate::api::guards;
|
||||
use crate::services::providers::{ConsentMethode, ProviderAction, Providers};
|
||||
use crate::errors::AutoDecryptError;
|
||||
use crate::main;
|
||||
use crate::orm::structures::{ProviderRecord};
|
||||
use crate::orm::types::{AuthMethod, RecordStates};
|
||||
use crate::services::providers::{ConsentMethode, ProviderAction, Providers, ActionType};
|
||||
use crate::app_config::CONFIG;
|
||||
use crate::orm::DbConn;
|
||||
use diesel::expression::is_aggregate::No;
|
||||
use rocket::get;
|
||||
use rocket::http::Status;
|
||||
use rocket::State;
|
||||
use super::HttpResult;
|
||||
|
||||
async fn execute_action(action: &Providers, key: Option<&str>) -> Result<String, AutoDecryptError> {
|
||||
|
||||
async fn execute_action(action: &Providers) -> Result<String, String> {
|
||||
let action: &dyn ProviderAction = &action.execution_action;
|
||||
action.execute().await
|
||||
let exec_action = match &action.execution_action {
|
||||
ActionType::ForigneAction(forigne_action) => {
|
||||
&forigne_action.to_executable_action(key)? as &dyn ProviderAction
|
||||
},
|
||||
_ => &action.execution_action as &dyn ProviderAction,
|
||||
};
|
||||
|
||||
exec_action.execute().await
|
||||
}
|
||||
|
||||
|
||||
#[get("/<_>", rank = 1)]
|
||||
pub(super) async fn request_handler(guard: Result<APIProviderRequest<'_>, HttpResult>) -> (Status, HttpResult) {
|
||||
pub(super) async fn request_handler(guard: Result<APIProviderRequest<'_>, HttpResult>, db_conn: &State<DbConn>) -> (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
|
||||
@ -22,22 +36,35 @@ pub(super) async fn request_handler(guard: Result<APIProviderRequest<'_>, HttpRe
|
||||
return err.into();
|
||||
}
|
||||
let guard = guard.expect("A rejected request guard was able to perseed!");
|
||||
|
||||
let mut expires_at = None;
|
||||
let auth_methode: AuthMethod = AuthMethod::from(&guard.share.consent_methode);
|
||||
let result: HttpResult = match guard.share.consent_methode {
|
||||
ConsentMethode::None => {
|
||||
// We do not wait for constent, direct feedback is impleied
|
||||
match execute_action(guard.share).await {
|
||||
match execute_action(guard.share, None).await {
|
||||
Ok(response) => HttpResult::UnlockingSucceeded(response),
|
||||
Err(err) => HttpResult::UnlockingFailed(err),
|
||||
Err(err) => HttpResult::UnlockingFailed(err.to_string()),
|
||||
}
|
||||
},
|
||||
ConsentMethode::Boolean => {
|
||||
todo!()
|
||||
},
|
||||
ConsentMethode::PassheyHash(_) => {
|
||||
todo!()
|
||||
_ => {
|
||||
expires_at = Some(CONFIG.wait().user_confirmation_expiration);
|
||||
HttpResult::AckAuthReq("An auth request has been sent.".to_string())
|
||||
},
|
||||
};
|
||||
let record_state = match &result {
|
||||
HttpResult::UnlockingSucceeded(_) => RecordStates::Accepted,
|
||||
HttpResult::AckAuthReq(_) => RecordStates::Pending,
|
||||
HttpResult::TimelimitExceeded(_) => RecordStates::Expired,
|
||||
_ => RecordStates::Rejected,
|
||||
};
|
||||
|
||||
db_conn.add_provider_record(&ProviderRecord {
|
||||
service_name: guard.name.to_string(),
|
||||
expires_at: expires_at, // Convert to sql timestamp + add used auth methode to record in db
|
||||
auth_methode: auth_methode,
|
||||
state: record_state,
|
||||
awnsered_by: None,
|
||||
});
|
||||
return result.into();
|
||||
|
||||
}
|
||||
@ -8,6 +8,7 @@ pub (super) struct TomlAppConfig {
|
||||
pub (super) addresses: Option<Vec<String>>,
|
||||
pub (super) platform: Option<Platform>,
|
||||
pub (super) ssh_known_host_file: Option<String>,
|
||||
pub (super) user_confirmation_expiration: Option<i64>,
|
||||
pub (super) db_file: Option<String>,
|
||||
pub (super) beggars: Option<HashMap<String, Beggars>>,
|
||||
pub (super) providers: Option<HashMap<String, TomlProviders>>
|
||||
|
||||
@ -22,7 +22,7 @@ pub(crate) struct AppConfig {
|
||||
pub(crate) addresses: Vec<String>,
|
||||
pub(crate) platform: Platform,
|
||||
pub(crate) ssh_known_host_file: String,
|
||||
|
||||
pub(crate) user_confirmation_expiration: i64,
|
||||
pub(crate) db_file: String,
|
||||
|
||||
pub(crate) beggars: HashMap<String, Beggars>, // We request to unlock owned services
|
||||
@ -36,6 +36,7 @@ impl Default for AppConfig {
|
||||
addresses: vec!["*".to_string()],
|
||||
beggars: HashMap::new(),
|
||||
providers: HashMap::new(),
|
||||
user_confirmation_expiration: 60 * 60 * 24, // 24 hours
|
||||
platform: Platform::OMV,
|
||||
ssh_known_host_file: "".to_string(),
|
||||
db_file: "/var/auto-decrypt/db.sqlite".to_string(),
|
||||
@ -51,6 +52,7 @@ impl 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),
|
||||
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),
|
||||
db_file: toml_config.db_file.unwrap_or(default.db_file),
|
||||
beggars: toml_config.beggars.unwrap_or(default.beggars),
|
||||
|
||||
@ -17,7 +17,7 @@ pub (super) struct TomlProviders {
|
||||
|
||||
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 let ActionType::ForigneAction(ref mut action_type) = self.execution_action {
|
||||
if action_type.content.is_none() {
|
||||
action_type.load_from_file(base_config_dir)?;
|
||||
}
|
||||
|
||||
@ -6,16 +6,17 @@ use super::DbConn;
|
||||
use super::structures::*;
|
||||
use crate::orm::schema::{providers_records, beggars_records};
|
||||
|
||||
use super::types::RecordStates;
|
||||
|
||||
impl DbConn {
|
||||
fn add_provider_record(self, record: &ProviderRecord) {
|
||||
pub(crate) fn add_provider_record(&self, record: &ProviderRecord) {
|
||||
let conn = &mut *self.0.lock().unwrap();
|
||||
diesel::insert_into(providers_records::table)
|
||||
.values(record)
|
||||
.execute(conn)
|
||||
.expect("Error saving new service record");
|
||||
}
|
||||
fn update_provider_state(self, id: i32, new_state: RecordStates) {
|
||||
pub(crate) fn update_provider_state(&self, id: i32, new_state: RecordStates) {
|
||||
let conn = &mut *self.0.lock().unwrap();
|
||||
diesel::update(providers_records::table.filter(providers_records::dsl::id.eq(id)))
|
||||
.set(providers_records::state.eq(new_state.to_string()))
|
||||
@ -23,7 +24,7 @@ impl DbConn {
|
||||
.expect("Error updating service record state");
|
||||
}
|
||||
|
||||
fn add_beggars_record(self, record: &BeggarsRecord) {
|
||||
pub(crate) fn add_beggars_record(&self, record: &BeggarsRecord) {
|
||||
let conn = &mut *self.0.lock().unwrap();
|
||||
diesel::insert_into(beggars_records::table)
|
||||
.values(record)
|
||||
|
||||
@ -4,8 +4,10 @@ use std::sync::{Arc, Mutex};
|
||||
|
||||
mod schema;
|
||||
mod handler;
|
||||
pub mod types;
|
||||
pub mod structures;
|
||||
|
||||
|
||||
pub struct DbConn(pub Arc<Mutex<SqliteConnection>>);
|
||||
|
||||
impl DbConn {
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
// @generated automatically by Diesel CLI.
|
||||
|
||||
diesel::table! {
|
||||
beggars_records (request_time) {
|
||||
request_time -> Timestamp,
|
||||
beggars_records (id) {
|
||||
id -> Nullable<Integer>,
|
||||
request_time -> BigInt,
|
||||
service_name -> Text,
|
||||
http_result -> Integer,
|
||||
note -> Nullable<Text>,
|
||||
@ -14,10 +15,11 @@ diesel::table! {
|
||||
providers_records (id) {
|
||||
id -> Nullable<Integer>,
|
||||
service_name -> Text,
|
||||
request_time -> Nullable<Timestamp>,
|
||||
expires_at -> Nullable<Timestamp>,
|
||||
request_time -> BigInt,
|
||||
auth_methode -> Text,
|
||||
expires_at -> Nullable<BigInt>,
|
||||
state -> Text,
|
||||
awnsered_at -> Nullable<Timestamp>,
|
||||
awnsered_at -> Nullable<BigInt>,
|
||||
awnsered_by -> Nullable<Text>,
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,65 +10,18 @@ use diesel::{
|
||||
AsExpression, FromSqlRow,
|
||||
};
|
||||
use std::fmt;
|
||||
|
||||
|
||||
#[derive(FromSqlRow, Debug, AsExpression)]
|
||||
#[diesel(sql_type = Text)]
|
||||
pub(crate) enum RecordStates {
|
||||
Pending,
|
||||
Accepted,
|
||||
Rejected,
|
||||
Expired,
|
||||
}
|
||||
|
||||
impl fmt::Display for RecordStates {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
RecordStates::Pending => write!(f, "Pending"),
|
||||
RecordStates::Accepted => write!(f, "Accepted"),
|
||||
RecordStates::Rejected => write!(f, "Rejected"),
|
||||
RecordStates::Expired => write!(f, "Expired"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for RecordStates {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
"Pending" => Ok(RecordStates::Pending),
|
||||
"Accepted" => Ok(RecordStates::Accepted),
|
||||
"Rejected" => Ok(RecordStates::Rejected),
|
||||
"Expired" => Ok(RecordStates::Expired),
|
||||
_ => Err(format!("Unknown state: {}", value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromSql<Text, Sqlite> for RecordStates {
|
||||
fn from_sql(bytes: SqliteValue) -> diesel::deserialize::Result<Self> {
|
||||
let t = <String as FromSql<Text, Sqlite>>::from_sql(bytes)?;
|
||||
Ok(t.as_str().try_into()?)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToSql<Text, Sqlite> for RecordStates {
|
||||
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Sqlite>) -> diesel::serialize::Result {
|
||||
out.set_value(self.to_string());
|
||||
Ok(diesel::serialize::IsNull::No)
|
||||
}
|
||||
}
|
||||
use super::types::{RecordStates, AuthMethod};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Queryable, Selectable, Insertable)]
|
||||
#[diesel(table_name = super::schema::providers_records)]
|
||||
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
||||
pub(crate) struct ProviderRecord{
|
||||
service_name: String,
|
||||
expires_at: Option<String>,
|
||||
state: RecordStates,
|
||||
awnsered_by: Option<String>,
|
||||
pub(crate) service_name: String,
|
||||
pub(crate) expires_at: Option<i64>, // Unix timestamp
|
||||
pub(crate) auth_methode: AuthMethod,
|
||||
pub(crate) state: RecordStates,
|
||||
pub(crate) awnsered_by: Option<String>,
|
||||
}
|
||||
|
||||
|
||||
|
||||
118
src/orm/types.rs
Normal file
118
src/orm/types.rs
Normal file
@ -0,0 +1,118 @@
|
||||
use clap::builder::Str;
|
||||
use diesel::{
|
||||
deserialize::FromSql,
|
||||
serialize::{Output, ToSql},
|
||||
sql_types::Text,
|
||||
Queryable,
|
||||
Selectable,
|
||||
Insertable,
|
||||
sqlite::{Sqlite, SqliteValue},
|
||||
AsExpression, FromSqlRow,
|
||||
};
|
||||
use std::fmt;
|
||||
use diesel::sql_types::BigInt;
|
||||
|
||||
#[derive(FromSqlRow, Debug, AsExpression)]
|
||||
#[diesel(sql_type = Text)]
|
||||
pub(crate) enum RecordStates {
|
||||
Pending,
|
||||
Accepted,
|
||||
Rejected,
|
||||
Expired,
|
||||
}
|
||||
|
||||
impl fmt::Display for RecordStates {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
RecordStates::Pending => write!(f, "Pending"),
|
||||
RecordStates::Accepted => write!(f, "Accepted"),
|
||||
RecordStates::Rejected => write!(f, "Rejected"),
|
||||
RecordStates::Expired => write!(f, "Expired"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for RecordStates {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
"Pending" => Ok(RecordStates::Pending),
|
||||
"Accepted" => Ok(RecordStates::Accepted),
|
||||
"Rejected" => Ok(RecordStates::Rejected),
|
||||
"Expired" => Ok(RecordStates::Expired),
|
||||
_ => Err(format!("Unknown state: {}", value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromSql<Text, Sqlite> for RecordStates {
|
||||
fn from_sql(bytes: SqliteValue) -> diesel::deserialize::Result<Self> {
|
||||
let t = <String as FromSql<Text, Sqlite>>::from_sql(bytes)?;
|
||||
Ok(t.as_str().try_into()?)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToSql<Text, Sqlite> for RecordStates {
|
||||
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Sqlite>) -> diesel::serialize::Result {
|
||||
out.set_value(self.to_string());
|
||||
Ok(diesel::serialize::IsNull::No)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(FromSqlRow, Debug, AsExpression)]
|
||||
#[diesel(sql_type = Text)]
|
||||
pub(crate) enum AuthMethod {
|
||||
None,
|
||||
Password,
|
||||
Confirmation,
|
||||
}
|
||||
impl fmt::Display for AuthMethod {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
AuthMethod::None => write!(f, "None"),
|
||||
AuthMethod::Password => write!(f, "Password"),
|
||||
AuthMethod::Confirmation => write!(f, "Confirmation"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for AuthMethod {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
"None" => Ok(AuthMethod::None),
|
||||
"Password" => Ok(AuthMethod::Password),
|
||||
"Confirmation" => Ok(AuthMethod::Confirmation),
|
||||
_ => Err(format!("Unknown auth method: {}", value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromSql<Text, Sqlite> for AuthMethod {
|
||||
fn from_sql(bytes: SqliteValue) -> diesel::deserialize::Result<Self> {
|
||||
let t = <String as FromSql<Text, Sqlite>>::from_sql(bytes)?;
|
||||
Ok(t.as_str().try_into()?)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToSql<Text, Sqlite> for AuthMethod {
|
||||
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Sqlite>) -> diesel::serialize::Result {
|
||||
out.set_value(self.to_string());
|
||||
Ok(diesel::serialize::IsNull::No)
|
||||
}
|
||||
}
|
||||
|
||||
use crate::services::providers::ConsentMethode;
|
||||
|
||||
impl From<&ConsentMethode> for AuthMethod {
|
||||
fn from(value: &ConsentMethode) -> Self {
|
||||
match value {
|
||||
ConsentMethode::Boolean => AuthMethod::Confirmation,
|
||||
ConsentMethode::PasskeyHash(_) => AuthMethod::Password,
|
||||
_ => AuthMethod::None
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
use std::f32::consts::E;
|
||||
use std::path::Path;
|
||||
|
||||
use async_ssh2_tokio::Config;
|
||||
@ -17,15 +18,16 @@ use crate::errors::AutoDecryptError;
|
||||
pub(crate) enum ConsentMethode {
|
||||
None,
|
||||
Boolean,
|
||||
PassheyHash(String),
|
||||
PasskeyHash(String),
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[enum_dispatch(ProviderAction)]
|
||||
pub(crate) enum ActionType {
|
||||
HTTPRequest(HTTPAction),
|
||||
SSHRequest(SSHAction),
|
||||
EncryptedRequest(EncryptedAction)
|
||||
ForigneAction(ForigneAction)
|
||||
}
|
||||
|
||||
|
||||
@ -49,24 +51,24 @@ struct HTTPAction {
|
||||
|
||||
#[async_trait]
|
||||
impl ProviderAction for HTTPAction {
|
||||
async fn execute(&self) -> Result<String, String> {
|
||||
async fn execute(&self) -> Result<String, AutoDecryptError> {
|
||||
let client = Client::new();
|
||||
let mut req_builder = client.request(
|
||||
reqwest::Method::from_bytes(self.method.as_bytes())
|
||||
.map_err(|e| e.to_string())?,
|
||||
.map_err(|e| AutoDecryptError::ConfigurationError { comment: 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())?,
|
||||
HeaderName::from_bytes(key.as_bytes()).map_err(|e| AutoDecryptError::ConfigurationError { comment: e.to_string() })?,
|
||||
HeaderValue::from_str(value).map_err(|e| AutoDecryptError::ConfigurationError { comment: 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())?))
|
||||
.map_err(|e| AutoDecryptError::APIError { comment: e.to_string() })?;
|
||||
Ok(format!("Success! Server replied with: {}", response.text().await.map_err(|e| AutoDecryptError::APIError { comment: e.to_string() })?))
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,31 +83,34 @@ struct SSHAction {
|
||||
|
||||
#[async_trait]
|
||||
impl ProviderAction for SSHAction {
|
||||
async fn execute(&self) -> Result<String, String> {
|
||||
async fn execute(&self) -> Result<String, AutoDecryptError> {
|
||||
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())?;
|
||||
).await.map_err(|e| AutoDecryptError::APIError { comment: e.to_string() })?;
|
||||
|
||||
let result = client.execute(&self.cmd).await.map_err(|e| e.to_string())?;
|
||||
let result = client.execute(&self.cmd).await.map_err(|e| AutoDecryptError::APIError { comment: e.to_string() })?;
|
||||
if result.exit_status == 0 {
|
||||
Ok(result.stdout)
|
||||
} else {
|
||||
Err(result.stderr)
|
||||
Err(AutoDecryptError::APIError {
|
||||
comment: format!("SSH command failed with exit status {}: {}", result.exit_status, result.stderr),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct EncryptedAction{
|
||||
pub struct ForigneAction{
|
||||
pub(crate) filename: String,
|
||||
pub(crate) content: Option<String>
|
||||
pub(crate) content: Option<String>,
|
||||
pub(crate) is_encrypted: bool,
|
||||
}
|
||||
impl ProviderAction for EncryptedAction {}
|
||||
impl EncryptedAction {
|
||||
impl ProviderAction for ForigneAction {}
|
||||
impl ForigneAction {
|
||||
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() })?;
|
||||
@ -114,7 +119,7 @@ impl EncryptedAction {
|
||||
}
|
||||
|
||||
|
||||
async fn to_executable_action(&self, key: &str) -> Result<ActionType, AutoDecryptError> {
|
||||
pub(crate) fn to_executable_action(&self, key: Option<&str>) -> Result<ActionType, AutoDecryptError> {
|
||||
todo!()
|
||||
//let cleartext_toml =
|
||||
//1. get Cleartext toml 2. load tomel as any other 3. return object
|
||||
@ -127,7 +132,7 @@ impl EncryptedAction {
|
||||
#[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())
|
||||
async fn execute(&self) -> Result<String, AutoDecryptError> {
|
||||
return Err(AutoDecryptError::ConfigurationError { comment: ("We are not directly executable!".to_string()) })
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user