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`
|
-- 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
|
-- Your SQL goes here
|
||||||
CREATE TABLE sessions (
|
CREATE TABLE providers_records (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
service_name TEXT NOT NULL,
|
service_name TEXT NOT NULL,
|
||||||
request_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
request_time BIGINT UNSIGNED NOT NULL,
|
||||||
expires_at TIMESTAMP,
|
auth_methode TEXT NOT NULL,
|
||||||
|
expires_at BIGINT UNSIGNED,
|
||||||
state TEXT NOT NULL,
|
state TEXT NOT NULL,
|
||||||
awnsered_at TIMESTAMP,
|
awnsered_at BIGINT UNSIGNED,
|
||||||
awnsered_by TEXT
|
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(super) struct APIProviderRequest<'r> {
|
||||||
pub share: &'r Providers,
|
pub share: &'r Providers,
|
||||||
|
pub name: &'r str,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rocket::async_trait]
|
#[rocket::async_trait]
|
||||||
@ -49,7 +50,7 @@ impl<'r> FromRequest<'r> for APIProviderRequest<'r> {
|
|||||||
.iter()
|
.iter()
|
||||||
.find(|(name, service)| *name == share_name && service.access_key_hash == access_key)
|
.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 {
|
} else {
|
||||||
Outcome::Error(HttpResult::ShareNotFound(format!(
|
Outcome::Error(HttpResult::ShareNotFound(format!(
|
||||||
"Share '{}' not found.",
|
"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 super::guards::APIProviderRequest;
|
||||||
use crate::api::guards;
|
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::app_config::CONFIG;
|
||||||
|
use crate::orm::DbConn;
|
||||||
|
use diesel::expression::is_aggregate::No;
|
||||||
use rocket::get;
|
use rocket::get;
|
||||||
use rocket::http::Status;
|
use rocket::http::Status;
|
||||||
|
use rocket::State;
|
||||||
use super::HttpResult;
|
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 exec_action = match &action.execution_action {
|
||||||
let action: &dyn ProviderAction = &action.execution_action;
|
ActionType::ForigneAction(forigne_action) => {
|
||||||
action.execute().await
|
&forigne_action.to_executable_action(key)? as &dyn ProviderAction
|
||||||
|
},
|
||||||
|
_ => &action.execution_action as &dyn ProviderAction,
|
||||||
|
};
|
||||||
|
|
||||||
|
exec_action.execute().await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[get("/<_>", rank = 1)]
|
#[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
|
// We assume the request guard verified th access_key against the service_name
|
||||||
if let Err(err) = guard {
|
if let Err(err) = guard {
|
||||||
// This wrapper is nessesary to avoid needing to write catchers, and recompute the error
|
// 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();
|
return err.into();
|
||||||
}
|
}
|
||||||
let guard = guard.expect("A rejected request guard was able to perseed!");
|
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 {
|
let result: HttpResult = match guard.share.consent_methode {
|
||||||
ConsentMethode::None => {
|
ConsentMethode::None => {
|
||||||
// We do not wait for constent, direct feedback is impleied
|
// 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),
|
Ok(response) => HttpResult::UnlockingSucceeded(response),
|
||||||
Err(err) => HttpResult::UnlockingFailed(err),
|
Err(err) => HttpResult::UnlockingFailed(err.to_string()),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ConsentMethode::Boolean => {
|
_ => {
|
||||||
todo!()
|
expires_at = Some(CONFIG.wait().user_confirmation_expiration);
|
||||||
},
|
HttpResult::AckAuthReq("An auth request has been sent.".to_string())
|
||||||
ConsentMethode::PassheyHash(_) => {
|
|
||||||
todo!()
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
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();
|
return result.into();
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -8,6 +8,7 @@ pub (super) struct TomlAppConfig {
|
|||||||
pub (super) addresses: Option<Vec<String>>,
|
pub (super) addresses: Option<Vec<String>>,
|
||||||
pub (super) platform: Option<Platform>,
|
pub (super) platform: Option<Platform>,
|
||||||
pub (super) ssh_known_host_file: Option<String>,
|
pub (super) ssh_known_host_file: Option<String>,
|
||||||
|
pub (super) user_confirmation_expiration: Option<i64>,
|
||||||
pub (super) db_file: Option<String>,
|
pub (super) db_file: Option<String>,
|
||||||
pub (super) beggars: Option<HashMap<String, Beggars>>,
|
pub (super) beggars: Option<HashMap<String, Beggars>>,
|
||||||
pub (super) providers: Option<HashMap<String, TomlProviders>>
|
pub (super) providers: Option<HashMap<String, TomlProviders>>
|
||||||
|
|||||||
@ -22,7 +22,7 @@ pub(crate) struct AppConfig {
|
|||||||
pub(crate) addresses: Vec<String>,
|
pub(crate) addresses: Vec<String>,
|
||||||
pub(crate) platform: Platform,
|
pub(crate) platform: Platform,
|
||||||
pub(crate) ssh_known_host_file: String,
|
pub(crate) ssh_known_host_file: String,
|
||||||
|
pub(crate) user_confirmation_expiration: i64,
|
||||||
pub(crate) db_file: String,
|
pub(crate) db_file: 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
|
||||||
@ -36,6 +36,7 @@ impl Default for AppConfig {
|
|||||||
addresses: vec!["*".to_string()],
|
addresses: vec!["*".to_string()],
|
||||||
beggars: HashMap::new(),
|
beggars: HashMap::new(),
|
||||||
providers: HashMap::new(),
|
providers: HashMap::new(),
|
||||||
|
user_confirmation_expiration: 60 * 60 * 24, // 24 hours
|
||||||
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(),
|
||||||
@ -51,6 +52,7 @@ impl AppConfig {
|
|||||||
port: toml_config.port.unwrap_or(default.port),
|
port: toml_config.port.unwrap_or(default.port),
|
||||||
addresses: toml_config.addresses.unwrap_or(default.addresses),
|
addresses: toml_config.addresses.unwrap_or(default.addresses),
|
||||||
platform: toml_config.platform.unwrap_or(default.platform),
|
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),
|
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),
|
||||||
beggars: toml_config.beggars.unwrap_or(default.beggars),
|
beggars: toml_config.beggars.unwrap_or(default.beggars),
|
||||||
|
|||||||
@ -17,7 +17,7 @@ pub (super) struct TomlProviders {
|
|||||||
|
|
||||||
impl TomlProviders {
|
impl TomlProviders {
|
||||||
pub(super) fn to_internal(mut self, base_config_dir: &Path) -> Result<Providers, AutoDecryptError> {
|
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() {
|
if action_type.content.is_none() {
|
||||||
action_type.load_from_file(base_config_dir)?;
|
action_type.load_from_file(base_config_dir)?;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,16 +6,17 @@ use super::DbConn;
|
|||||||
use super::structures::*;
|
use super::structures::*;
|
||||||
use crate::orm::schema::{providers_records, beggars_records};
|
use crate::orm::schema::{providers_records, beggars_records};
|
||||||
|
|
||||||
|
use super::types::RecordStates;
|
||||||
|
|
||||||
impl DbConn {
|
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();
|
let conn = &mut *self.0.lock().unwrap();
|
||||||
diesel::insert_into(providers_records::table)
|
diesel::insert_into(providers_records::table)
|
||||||
.values(record)
|
.values(record)
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
.expect("Error saving new service record");
|
.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();
|
let conn = &mut *self.0.lock().unwrap();
|
||||||
diesel::update(providers_records::table.filter(providers_records::dsl::id.eq(id)))
|
diesel::update(providers_records::table.filter(providers_records::dsl::id.eq(id)))
|
||||||
.set(providers_records::state.eq(new_state.to_string()))
|
.set(providers_records::state.eq(new_state.to_string()))
|
||||||
@ -23,7 +24,7 @@ impl DbConn {
|
|||||||
.expect("Error updating service record state");
|
.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();
|
let conn = &mut *self.0.lock().unwrap();
|
||||||
diesel::insert_into(beggars_records::table)
|
diesel::insert_into(beggars_records::table)
|
||||||
.values(record)
|
.values(record)
|
||||||
|
|||||||
@ -4,8 +4,10 @@ use std::sync::{Arc, Mutex};
|
|||||||
|
|
||||||
mod schema;
|
mod schema;
|
||||||
mod handler;
|
mod handler;
|
||||||
|
pub mod types;
|
||||||
pub mod structures;
|
pub mod structures;
|
||||||
|
|
||||||
|
|
||||||
pub struct DbConn(pub Arc<Mutex<SqliteConnection>>);
|
pub struct DbConn(pub Arc<Mutex<SqliteConnection>>);
|
||||||
|
|
||||||
impl DbConn {
|
impl DbConn {
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
// @generated automatically by Diesel CLI.
|
// @generated automatically by Diesel CLI.
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
beggars_records (request_time) {
|
beggars_records (id) {
|
||||||
request_time -> Timestamp,
|
id -> Nullable<Integer>,
|
||||||
|
request_time -> BigInt,
|
||||||
service_name -> Text,
|
service_name -> Text,
|
||||||
http_result -> Integer,
|
http_result -> Integer,
|
||||||
note -> Nullable<Text>,
|
note -> Nullable<Text>,
|
||||||
@ -14,10 +15,11 @@ diesel::table! {
|
|||||||
providers_records (id) {
|
providers_records (id) {
|
||||||
id -> Nullable<Integer>,
|
id -> Nullable<Integer>,
|
||||||
service_name -> Text,
|
service_name -> Text,
|
||||||
request_time -> Nullable<Timestamp>,
|
request_time -> BigInt,
|
||||||
expires_at -> Nullable<Timestamp>,
|
auth_methode -> Text,
|
||||||
|
expires_at -> Nullable<BigInt>,
|
||||||
state -> Text,
|
state -> Text,
|
||||||
awnsered_at -> Nullable<Timestamp>,
|
awnsered_at -> Nullable<BigInt>,
|
||||||
awnsered_by -> Nullable<Text>,
|
awnsered_by -> Nullable<Text>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,65 +10,18 @@ use diesel::{
|
|||||||
AsExpression, FromSqlRow,
|
AsExpression, FromSqlRow,
|
||||||
};
|
};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use super::types::{RecordStates, AuthMethod};
|
||||||
|
|
||||||
#[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(Debug)]
|
#[derive(Debug)]
|
||||||
#[derive(Queryable, Selectable, Insertable)]
|
#[derive(Queryable, Selectable, Insertable)]
|
||||||
#[diesel(table_name = super::schema::providers_records)]
|
#[diesel(table_name = super::schema::providers_records)]
|
||||||
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
||||||
pub(crate) struct ProviderRecord{
|
pub(crate) struct ProviderRecord{
|
||||||
service_name: String,
|
pub(crate) service_name: String,
|
||||||
expires_at: Option<String>,
|
pub(crate) expires_at: Option<i64>, // Unix timestamp
|
||||||
state: RecordStates,
|
pub(crate) auth_methode: AuthMethod,
|
||||||
awnsered_by: Option<String>,
|
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 std::path::Path;
|
||||||
|
|
||||||
use async_ssh2_tokio::Config;
|
use async_ssh2_tokio::Config;
|
||||||
@ -17,15 +18,16 @@ use crate::errors::AutoDecryptError;
|
|||||||
pub(crate) enum ConsentMethode {
|
pub(crate) enum ConsentMethode {
|
||||||
None,
|
None,
|
||||||
Boolean,
|
Boolean,
|
||||||
PassheyHash(String),
|
PasskeyHash(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
#[enum_dispatch(ProviderAction)]
|
#[enum_dispatch(ProviderAction)]
|
||||||
pub(crate) enum ActionType {
|
pub(crate) enum ActionType {
|
||||||
HTTPRequest(HTTPAction),
|
HTTPRequest(HTTPAction),
|
||||||
SSHRequest(SSHAction),
|
SSHRequest(SSHAction),
|
||||||
EncryptedRequest(EncryptedAction)
|
ForigneAction(ForigneAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -49,24 +51,24 @@ struct HTTPAction {
|
|||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl ProviderAction for HTTPAction {
|
impl ProviderAction for HTTPAction {
|
||||||
async fn execute(&self) -> Result<String, String> {
|
async fn execute(&self) -> Result<String, AutoDecryptError> {
|
||||||
let client = Client::new();
|
let client = Client::new();
|
||||||
let mut req_builder = client.request(
|
let mut req_builder = client.request(
|
||||||
reqwest::Method::from_bytes(self.method.as_bytes())
|
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,
|
&self.uri,
|
||||||
);
|
);
|
||||||
if let Some(headers) = &self.headers {
|
if let Some(headers) = &self.headers {
|
||||||
for (key, value) in headers {
|
for (key, value) in headers {
|
||||||
req_builder = req_builder.header(
|
req_builder = req_builder.header(
|
||||||
HeaderName::from_bytes(key.as_bytes()).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| e.to_string())?,
|
HeaderValue::from_str(value).map_err(|e| AutoDecryptError::ConfigurationError { comment: e.to_string() })?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let response = req_builder.send().await
|
let response = req_builder.send().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| 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]
|
#[async_trait]
|
||||||
impl ProviderAction for SSHAction {
|
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 auth_method = AuthMethod::PrivateKey { key_data: self.private_key.clone(), key_pass: None };
|
||||||
let client = SSHClient::connect(
|
let client = SSHClient::connect(
|
||||||
(&*self.uri, self.port),
|
(&*self.uri, self.port),
|
||||||
&self.username,
|
&self.username,
|
||||||
auth_method,
|
auth_method,
|
||||||
ServerCheckMethod::KnownHostsFile(CONFIG.wait().ssh_known_host_file.clone()),
|
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 {
|
if result.exit_status == 0 {
|
||||||
Ok(result.stdout)
|
Ok(result.stdout)
|
||||||
} else {
|
} else {
|
||||||
Err(result.stderr)
|
Err(AutoDecryptError::APIError {
|
||||||
|
comment: format!("SSH command failed with exit status {}: {}", result.exit_status, result.stderr),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct EncryptedAction{
|
pub struct ForigneAction{
|
||||||
pub(crate) filename: String,
|
pub(crate) filename: String,
|
||||||
pub(crate) content: Option<String>
|
pub(crate) content: Option<String>,
|
||||||
|
pub(crate) is_encrypted: bool,
|
||||||
}
|
}
|
||||||
impl ProviderAction for EncryptedAction {}
|
impl ProviderAction for ForigneAction {}
|
||||||
impl EncryptedAction {
|
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: 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!()
|
todo!()
|
||||||
//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
|
||||||
@ -127,7 +132,7 @@ impl EncryptedAction {
|
|||||||
#[async_trait]
|
#[async_trait]
|
||||||
#[enum_dispatch]
|
#[enum_dispatch]
|
||||||
pub (crate) trait ProviderAction: std::fmt::Debug + Send + Sync {
|
pub (crate) trait ProviderAction: std::fmt::Debug + Send + Sync {
|
||||||
async fn execute(&self) -> Result<String, String> {
|
async fn execute(&self) -> Result<String, AutoDecryptError> {
|
||||||
return Err("We are not directly executable!".to_string())
|
return Err(AutoDecryptError::ConfigurationError { comment: ("We are not directly executable!".to_string()) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user