Logic to resolve mount points
This commit is contained in:
parent
049e8374ab
commit
a5d74f0454
4 changed files with 63 additions and 41 deletions
|
|
@ -3,6 +3,7 @@ pub mod kv;
|
||||||
use axum::{
|
use axum::{
|
||||||
body::Body,
|
body::Body,
|
||||||
extract::{Request, State},
|
extract::{Request, State},
|
||||||
|
http::Uri,
|
||||||
response::Response,
|
response::Response,
|
||||||
Router,
|
Router,
|
||||||
};
|
};
|
||||||
|
|
@ -11,35 +12,46 @@ use log::*;
|
||||||
use crate::storage::DatabaseDriver;
|
use crate::storage::DatabaseDriver;
|
||||||
|
|
||||||
pub fn secrets_router(pool: DatabaseDriver) -> Router<DatabaseDriver> {
|
pub fn secrets_router(pool: DatabaseDriver) -> Router<DatabaseDriver> {
|
||||||
Router::new().fallback(map_mount_points).with_state(pool)
|
Router::new().fallback(engine_handler).with_state(pool)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn map_mount_points(State(pool): State<DatabaseDriver>, req: Request) -> Response<Body> {
|
async fn engine_handler(State(pool): State<DatabaseDriver>, req: Request) -> Response<Body> {
|
||||||
debug!("Mount path: {:?}", req);
|
match map_mount_points(req.uri(), &pool).await {
|
||||||
|
Some((mount_path, engine_type)) => {
|
||||||
let mut mount_path: Vec<&str> = req.uri().path().split("/").collect();
|
info!("Found mount point {} of type {}", mount_path, engine_type);
|
||||||
|
todo!()
|
||||||
// let a = sqlx::query!("SELECT * FROM secret_engines WHERE path = $1", mount_path.join("/"))
|
|
||||||
// .fetch_one(&pool)
|
|
||||||
// .await
|
|
||||||
// .expect("Failed to fetch secret engine");
|
|
||||||
|
|
||||||
let tada = vec!["a/b/c/d".to_string(), "/a/b/c".to_string(), "/kv-v2".into()];
|
|
||||||
|
|
||||||
// Find longest matching existing mount path for the request
|
|
||||||
for _ in 1..mount_path.len() {
|
|
||||||
if tada.contains(&mount_path.join("/")) {
|
|
||||||
trace!(
|
|
||||||
"Mount path {} found for route request: {}",
|
|
||||||
mount_path.join("/"),
|
|
||||||
req.uri().path()
|
|
||||||
);
|
|
||||||
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
mount_path.pop();
|
|
||||||
}
|
}
|
||||||
|
None => todo!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return Response::new(Body::from(format!("Mount path:")));
|
// Response::new(Body::from("Mount path:"))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn map_mount_points(req: &Uri, pool: &DatabaseDriver) -> Option<(String, String)> {
|
||||||
|
let mut mount_path_fragments: Vec<&str> = req.path().split('/').collect();
|
||||||
|
|
||||||
|
// Find longest matching existing mount path for the request
|
||||||
|
for _ in 1..mount_path_fragments.len() {
|
||||||
|
let path_str = mount_path_fragments.join("/");
|
||||||
|
let record = sqlx::query!(
|
||||||
|
"SELECT engine_type FROM secret_engines WHERE mount_point = $1",
|
||||||
|
path_str
|
||||||
|
)
|
||||||
|
.fetch_optional(pool)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
if let Ok(Some(row)) = record {
|
||||||
|
trace!(
|
||||||
|
"Mount path {} found with {:?} engine for route request: {}",
|
||||||
|
mount_path_fragments.join("/"),
|
||||||
|
row.engine_type,
|
||||||
|
req.path()
|
||||||
|
);
|
||||||
|
|
||||||
|
return Some((mount_path_fragments.join("/"), row.engine_type));
|
||||||
|
} else {
|
||||||
|
mount_path_fragments.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@ pub mod structs;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
use crate::{engines::kv::logic::body_to_json, storage::DatabaseDriver};
|
|
||||||
use crate::engines::kv::structs::KvSecret;
|
use crate::engines::kv::structs::KvSecret;
|
||||||
use axum::{routing::*, Router, extract::Path};
|
use crate::{engines::kv::logic::body_to_json, storage::DatabaseDriver};
|
||||||
|
use axum::{extract::Path, routing::*, Router};
|
||||||
|
|
||||||
pub fn kv_router(pool: DatabaseDriver) -> Router<DatabaseDriver> {
|
pub fn kv_router(pool: DatabaseDriver) -> Router<DatabaseDriver> {
|
||||||
Router::new()
|
Router::new()
|
||||||
|
|
@ -42,7 +42,10 @@ async fn get_data() -> &'static str {
|
||||||
todo!("not implemented")
|
todo!("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn post_data(Path((mount_path, kv_path)): Path<(String, String)>, body: String) -> &'static str {
|
async fn post_data(
|
||||||
|
Path((mount_path, kv_path)): Path<(String, String)>,
|
||||||
|
body: String,
|
||||||
|
) -> &'static str {
|
||||||
let mut body_json = body_to_json(body);
|
let mut body_json = body_to_json(body);
|
||||||
|
|
||||||
let secret: KvSecret = KvSecret {
|
let secret: KvSecret = KvSecret {
|
||||||
|
|
@ -61,8 +64,7 @@ async fn post_data(Path((mount_path, kv_path)): Path<(String, String)>, body: St
|
||||||
// todo!("not implemented")
|
// todo!("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// TODO: soft delete the secret version at path. can be undone with undelete_secret
|
||||||
/// TODO soft delete the secret version at path. can be undone with undelete_secret
|
|
||||||
// https://developer.hashicorp.com/vault/api-docs/secret/kv/kv-v2#delete-latest-version-of-secret
|
// https://developer.hashicorp.com/vault/api-docs/secret/kv/kv-v2#delete-latest-version-of-secret
|
||||||
// https://developer.hashicorp.com/vault/api-docs/secret/kv/kv-v2#delete-secret-versions
|
// https://developer.hashicorp.com/vault/api-docs/secret/kv/kv-v2#delete-secret-versions
|
||||||
async fn delete_data() -> &'static str {
|
async fn delete_data() -> &'static str {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use chrono::{DateTime, Utc};
|
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use super::structs::*;
|
use super::structs::*;
|
||||||
|
|
@ -14,7 +11,7 @@ pub fn serialize_secret_json(secret: &KvSecret) -> Result<String, serde_json::Er
|
||||||
|
|
||||||
/// deserialize JSON String to secret
|
/// deserialize JSON String to secret
|
||||||
pub fn deserialize_secret_struct(raw: &String) -> Result<KvSecret, serde_json::Error> {
|
pub fn deserialize_secret_struct(raw: &String) -> Result<KvSecret, serde_json::Error> {
|
||||||
serde_json::from_str(&raw)
|
serde_json::from_str(raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// serialize metadata to JSON String
|
/// serialize metadata to JSON String
|
||||||
|
|
@ -24,7 +21,7 @@ pub fn serialize_metadata_json(secret: &SecretMeta) -> Result<String, serde_json
|
||||||
|
|
||||||
/// deserialize JSON String to metadata
|
/// deserialize JSON String to metadata
|
||||||
pub fn deserialize_metadata_struct(raw: &String) -> Result<SecretMeta, serde_json::Error> {
|
pub fn deserialize_metadata_struct(raw: &String) -> Result<SecretMeta, serde_json::Error> {
|
||||||
serde_json::from_str(&raw)
|
serde_json::from_str(raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn patch_metadata(
|
pub fn patch_metadata(
|
||||||
|
|
@ -39,10 +36,10 @@ pub fn patch_metadata(
|
||||||
|
|
||||||
pub fn body_to_json(body: String) -> Value {
|
pub fn body_to_json(body: String) -> Value {
|
||||||
match serde_json::from_str::<serde_json::Value>(body.as_str()) {
|
match serde_json::from_str::<serde_json::Value>(body.as_str()) {
|
||||||
Ok(val) => return val,
|
Ok(val) => val,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::debug!("Faulty result from conversion: {:?}", e);
|
log::debug!("Faulty result from conversion: {:?}", e);
|
||||||
return Into::into("Error converting body");
|
"Error converting body".into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,15 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use chrono::Utc;
|
||||||
|
use tests::{
|
||||||
|
logic::patch_metadata,
|
||||||
|
structs::{SecretMeta, VersionMeta},
|
||||||
|
};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg(target_feature = "_disabled")]
|
||||||
fn print_serialized_test() {
|
fn print_serialized_test() {
|
||||||
let temp_secret = TempSecret {
|
let temp_secret = TempSecret {
|
||||||
content: String::from("Hallo"),
|
content: String::from("Hallo"),
|
||||||
|
|
@ -14,6 +24,7 @@ fn print_serialized_test() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg(target_feature = "_disabled")]
|
||||||
fn test_patching() {
|
fn test_patching() {
|
||||||
// TODO add more assertions
|
// TODO add more assertions
|
||||||
let mut base = create_mock_meta();
|
let mut base = create_mock_meta();
|
||||||
|
|
@ -31,7 +42,7 @@ fn test_patching() {
|
||||||
oldest_version: 2,
|
oldest_version: 2,
|
||||||
updated_time: Utc::now(),
|
updated_time: Utc::now(),
|
||||||
created_time: Utc::now(),
|
created_time: Utc::now(),
|
||||||
custom_metadata: HashMap::new(),
|
custom_metadata: Some(HashMap::new()),
|
||||||
};
|
};
|
||||||
let mut patched: Option<SecretMeta> = None; // Laurenz here
|
let mut patched: Option<SecretMeta> = None; // Laurenz here
|
||||||
match patch_metadata(&mut base, &overwrite) {
|
match patch_metadata(&mut base, &overwrite) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue