205 lines
6 KiB
Rust
205 lines
6 KiB
Rust
// TODO: Remove
|
|
#![allow(dead_code)]
|
|
|
|
// pub mod logic; // TODO: Remove or correct errors
|
|
pub mod http_structs;
|
|
pub mod db_structs;
|
|
|
|
// #[cfg(test)]
|
|
// mod tests;
|
|
|
|
use std::{collections::HashMap, convert::Infallible};
|
|
use serde_json;
|
|
use crate::{
|
|
engines::kv::http_structs::*,
|
|
storage::DatabaseDriver,
|
|
};
|
|
use axum::{
|
|
extract::{self, Path, State}, http::StatusCode, response::IntoResponse, routing::*, Json, Router
|
|
};
|
|
use chrono::{DateTime, Utc};
|
|
use log::{info, error};
|
|
use sqlx::{error, Row};
|
|
|
|
pub fn kv_router(pool: DatabaseDriver) -> Router {
|
|
Router::new()
|
|
.route("/config", get(get_config))
|
|
.route("/config", post(post_config))
|
|
.route("/data/*path", get(get_data))
|
|
// .route("/:mount_path/data/*path/", get(get_data))
|
|
.route("/data/*path", post(post_data))
|
|
.route("/data/*path", delete(delete_data))
|
|
.route("/delete/*path", post(delete_path))
|
|
.route("/destroy/*path", post(destroy_path))
|
|
.route("/metadata/*path", get(get_meta))
|
|
// .route("/:mount_path/metadata/*path/", get(get_meta))
|
|
.route("/metadata/*path", post(post_meta))
|
|
.route("/metadata/*path", delete(delete_meta))
|
|
.route("/subkeys/*path", get(get_subkeys))
|
|
.route("/undelete/*path", post(post_undelete))
|
|
.with_state(pool)
|
|
}
|
|
|
|
async fn get_config() -> &'static str {
|
|
todo!("not implemented")
|
|
}
|
|
|
|
async fn post_config() -> &'static str {
|
|
todo!("not implemented")
|
|
}
|
|
|
|
async fn get_data(
|
|
State(pool): State<DatabaseDriver>,
|
|
Path(path): Path<String>,
|
|
) -> Result<impl IntoResponse, Infallible> {
|
|
match sqlx::query("SELECT * FROM secret_versions WHERE secret_path = $1")
|
|
.bind(path)
|
|
.fetch_one(&pool)
|
|
.await
|
|
{
|
|
Ok(v) => {
|
|
let version: i64 = v.get("version_number");
|
|
let secret_content: HashMap<String, String> = HashMap::from([
|
|
// TODO: use sqlx to parse the row to a struct, do not do it manually
|
|
("secret_data".to_string(), v.get("secret_data")),
|
|
("created_time".to_string(), v.get("created_time")),
|
|
("deletion_time".to_string(), v.get("deletion_time")),
|
|
("version_number".to_string(), version.to_string()),
|
|
("secret_path".to_string(), v.get("secret_path")),
|
|
]);
|
|
let return_secret = KvSecretRes::new(KvSecretResData {
|
|
created_time: DateTime::parse_from_rfc3339(secret_content.get("created_time").unwrap_or(&"".to_string())).unwrap_or_default().to_utc(), // TODO
|
|
custom_metadata: None,
|
|
deletion_time: None, // TODO
|
|
destroyed: false,
|
|
version: version,
|
|
});
|
|
info!("{:?}", return_secret);
|
|
|
|
Ok((StatusCode::OK, Json(return_secret)).into_response())
|
|
}
|
|
Err(e) => match e {
|
|
sqlx::Error::RowNotFound => {
|
|
error!("{:?}", e);
|
|
let error_struct : ErrorStruct = ErrorStruct{err: e.to_string() };
|
|
error!("{:?}", error_struct.err);
|
|
Ok(error_struct.into_response()) // TODO: API doesn't specify return value in case of error. Error struct correct? Else send empty secret back?
|
|
// let error_secret = KvSecretRes{data: None, options: None};
|
|
// Ok(Json())
|
|
},
|
|
_ => panic!("{:?}", e),
|
|
},
|
|
}
|
|
}
|
|
|
|
async fn post_data(
|
|
State(pool): State<DatabaseDriver>,
|
|
Path(path): Path<String>,
|
|
extract::Json(payload): extract::Json<KvSecretReq>,
|
|
) -> &'static str {
|
|
// Insert Metadata first -> Else: Error because of foreign key constraint
|
|
|
|
|
|
log::debug!(
|
|
"Secret: {}, Content: {:?}, Version: {:?}, path: {}",
|
|
path,
|
|
payload.data,
|
|
payload.options,
|
|
path
|
|
);
|
|
|
|
|
|
let data = serde_json::to_string(&payload.data).unwrap();
|
|
log::debug!("Received data: {:?}", data);
|
|
let created_time = Utc::now().to_string();
|
|
let deletion_time = "12-12-2024 12:00:00"; // TODO:
|
|
let version = "1";
|
|
match sqlx::query(
|
|
"INSERT INTO secret_versions VALUES ($1, $2, $3, $4, $5)",
|
|
)
|
|
.bind(data)
|
|
.bind(created_time)
|
|
.bind (deletion_time)
|
|
.bind(version)
|
|
.bind(path)
|
|
.execute(&pool)
|
|
.await
|
|
{
|
|
Ok(v) => {
|
|
info!("{:?}", v);
|
|
}
|
|
Err(e) => {
|
|
error!("{:?}", e);
|
|
}
|
|
}
|
|
|
|
todo!("not implemented")
|
|
}
|
|
|
|
/* mock for return
|
|
async fn post_data(
|
|
Path(kv_path): Path<String>,
|
|
Extension(mount_path): Extension<String>,
|
|
Json(body): Json<KvSecretReq>,
|
|
) -> Json<KvSecretRes> {
|
|
trace!(
|
|
"Secret: {}, Content: {:#?}, path: {}",
|
|
kv_path,
|
|
body.data,
|
|
// body.version.unwrap_or(0),
|
|
mount_path,
|
|
);
|
|
|
|
let res = KvSecretRes {
|
|
data: KvSecretResData {
|
|
created_time: chrono::Utc::now(),
|
|
custom_metadata: None,
|
|
deletion_time: None,
|
|
destroyed: false,
|
|
version: 1,
|
|
},
|
|
};
|
|
|
|
Json(res)
|
|
} */
|
|
|
|
/// 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-secret-versions
|
|
async fn delete_data() -> &'static str {
|
|
todo!("not implemented")
|
|
}
|
|
|
|
async fn delete_path() -> &'static str {
|
|
todo!("not implemented")
|
|
}
|
|
|
|
async fn destroy_path() -> &'static str {
|
|
todo!("not implemented")
|
|
}
|
|
|
|
async fn get_meta() -> &'static str {
|
|
todo!("not implemented")
|
|
}
|
|
|
|
async fn post_meta(
|
|
State(pool): State<DatabaseDriver>,
|
|
Path((mount_path, kv_path)): Path<(String, String)>,
|
|
body: String,
|
|
) -> &'static str {
|
|
// let mut body_json = body_to_json(body);
|
|
// let meta_data: SecretMeta = Default::default();
|
|
todo!("not implemented")
|
|
}
|
|
|
|
async fn delete_meta() -> &'static str {
|
|
todo!("not implemented")
|
|
}
|
|
|
|
async fn get_subkeys() -> &'static str {
|
|
todo!("not implemented")
|
|
}
|
|
|
|
async fn post_undelete() -> &'static str {
|
|
todo!("not implemented")
|
|
}
|