+ basic metadata struct

+ unrefactored metadata utilities
This commit is contained in:
sam 2024-04-22 22:08:50 +02:00
parent 67bbb70d80
commit f91d396f69
4 changed files with 287 additions and 33 deletions

147
Cargo.lock generated
View file

@ -26,6 +26,21 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "android-tzdata"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "anstream" name = "anstream"
version = "0.6.13" version = "0.6.13"
@ -176,6 +191,7 @@ dependencies = [
name = "base" name = "base"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"chrono",
"serde", "serde",
"serde_json", "serde_json",
] ]
@ -186,6 +202,12 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bumpalo"
version = "3.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
[[package]] [[package]]
name = "byteorder" name = "byteorder"
version = "1.5.0" version = "1.5.0"
@ -210,12 +232,33 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
dependencies = [
"android-tzdata",
"iana-time-zone",
"js-sys",
"num-traits",
"serde",
"wasm-bindgen",
"windows-targets 0.52.5",
]
[[package]] [[package]]
name = "colorchoice" name = "colorchoice"
version = "1.0.0" version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "core-foundation-sys"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
[[package]] [[package]]
name = "crc32fast" name = "crc32fast"
version = "1.4.0" version = "1.4.0"
@ -441,6 +484,29 @@ dependencies = [
"tokio", "tokio",
] ]
[[package]]
name = "iana-time-zone"
version = "0.1.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
"windows-core",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "2.2.6" version = "2.2.6"
@ -467,6 +533,15 @@ version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "js-sys"
version = "0.3.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
dependencies = [
"wasm-bindgen",
]
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.153" version = "0.2.153"
@ -527,6 +602,15 @@ dependencies = [
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
[[package]]
name = "num-traits"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "num_cpus" name = "num_cpus"
version = "1.16.0" version = "1.16.0"
@ -1027,6 +1111,60 @@ version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.60",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.60",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.9" version = "0.3.9"
@ -1049,6 +1187,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-core"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
dependencies = [
"windows-targets 0.52.5",
]
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.48.0" version = "0.48.0"

View file

@ -7,5 +7,6 @@ edition = "2021"
workspace = true workspace = true
[dependencies] [dependencies]
chrono = { version = "0.4.38", features = ["serde"] }
serde = { version = "1.0.198", features = ["derive"] } serde = { version = "1.0.198", features = ["derive"] }
serde_json = "1.0.116" serde_json = "1.0.116"

View file

@ -1,39 +1,49 @@
pub fn add(left: usize, right: usize) -> usize {
left + right
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
#[test] #[test]
fn it_works() { fn print_serialized_test() {
let result = add(2, 2); let temp_secret = TempSecret {
assert_eq!(result, 4); content: String::from("Hallo"),
} version: 12,
#[test] };
fn print_serialized() {
let temp_secret = TempSecret { content: String::from("Hallo"), version: 12 };
let serialized = serialize_secret_json(&temp_secret); let serialized = serialize_secret_json(&temp_secret);
println!("string serialized: {:?}", serialized); println!("string serialized: {:?}", serialized);
let deserialized = deserialize_secret_struct(&serialized.unwrap()); let deserialized = deserialize_secret_struct(&serialized.unwrap());
println!("Struct field from deserialized: {}", deserialized.unwrap().content) println!(
"Struct field from deserialized: {}",
deserialized.unwrap().content
)
} }
} }
use serde::{Serialize, Deserialize}; pub fn create_mock_meta() -> SecretMeta {
SecretMeta {
cas_required: false,
created_time: DateTime::parse_from_rfc3339("2018-03-22T02:24:06.945319214Z")
.unwrap()
.with_timezone(&Utc),
current_version: 3,
delete_version_after: "3h25m19s".to_string(),
max_versions: 0,
oldest_version: 0,
updated_time: Utc::now(),
custom_metadata: HashMap::new(),
versions: vec![],
}
}
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct TempSecret { pub struct TempSecret {
pub content: String, pub content: String,
pub version: i64 pub version: i64,
} }
// /// serialize secret to JSON byte vector
// pub fn serialize_secret_json(secret: &TempSecret) -> Result<Vec<u8>> {
// serde_json::to_vec(&secret)
// }
/// serialize secret to JSON String /// serialize secret to JSON String
pub fn serialize_secret_json(secret: &TempSecret) -> Result<String, serde_json::Error> { pub fn serialize_secret_json(secret: &TempSecret) -> Result<String, serde_json::Error> {
serde_json::to_string(&secret) serde_json::to_string(&secret)
@ -43,3 +53,34 @@ pub fn serialize_secret_json(secret: &TempSecret) -> Result<String, serde_json::
pub fn deserialize_secret_struct(raw: &String) -> Result<TempSecret, serde_json::Error> { pub fn deserialize_secret_struct(raw: &String) -> Result<TempSecret, serde_json::Error> {
serde_json::from_str(&raw) serde_json::from_str(&raw)
} }
#[derive(Serialize, Deserialize, Debug)]
pub struct VersionMeta {
pub created_time: DateTime<Utc>,
pub deletion_time: DateTime<Utc>,
pub destroyed: bool,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct SecretMeta {
pub cas_required: bool,
pub created_time: DateTime<Utc>,
pub current_version: u32,
pub delete_version_after: String,
// TODO https://developer.hashicorp.com/vault/docs/concepts/duration-format
pub max_versions: u32,
pub oldest_version: u32,
pub updated_time: DateTime<Utc>,
pub custom_metadata: HashMap<String, String>,
pub versions: Vec<VersionMeta>,
}
/// serialize metadata to JSON String
pub fn serialize_metadata_json(secret: &SecretMeta) -> Result<String, serde_json::Error> {
serde_json::to_string(&secret)
}
/// deserialize JSON String to metadata
pub fn deserialize_metadata_struct(raw: &String) -> Result<SecretMeta, serde_json::Error> {
serde_json::from_str(&raw)
}

View file

@ -1,16 +1,7 @@
pub fn add(left: usize, right: usize) -> usize {
left + right
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use base::create_mock_meta;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
#[test] #[test]
fn test_update_secret() { fn test_update_secret() {
let db: sled::Db = sled::open("sled_db").unwrap(); let db: sled::Db = sled::open("sled_db").unwrap();
@ -26,10 +17,18 @@ mod tests {
let db: sled::Db = sled::open("sled_db").unwrap(); let db: sled::Db = sled::open("sled_db").unwrap();
delete_secret(&db, "foo"); delete_secret(&db, "foo");
} }
#[test]
fn test_meta(){
let db: sled::Db = sled::open("sled_db").unwrap();
println!("writing metadata:");
update_secret_meta(&db, "metatest", create_mock_meta());
println!("getting metadata:");
get_secretmeta(&db, "metatest");
}
} }
use sled::Db; use sled::Db;
use base::{deserialize_secret_struct, serialize_secret_json, TempSecret}; use base::{deserialize_metadata_struct, deserialize_secret_struct, serialize_metadata_json, serialize_secret_json, SecretMeta, TempSecret};
/// [TODO] Currently no proper versioning /// [TODO] Currently no proper versioning
/// inserts a secret. If there was already a secret in the given path, the version is incremented /// inserts a secret. If there was already a secret in the given path, the version is incremented
@ -64,6 +63,8 @@ fn update_secret(db: &Db, path: &str, mut secret: TempSecret) {
} }
} }
// !TODO eliminate redundancy: refactor get and update functions to accept generic types!
// read and return a secret from the DB // read and return a secret from the DB
//if there is no secret, return None //if there is no secret, return None
fn get_secret(db: &Db, path: &str) -> Option<TempSecret>{ fn get_secret(db: &Db, path: &str) -> Option<TempSecret>{
@ -96,7 +97,71 @@ fn get_secret(db: &Db, path: &str) -> Option<TempSecret>{
} }
} }
/// delete secret at path
// TODO write abstract get_something fn
// https://developer.hashicorp.com/vault/api-docs/secret/kv/kv-v2#read-secret-metadata
fn get_secretmeta(db: &Db, path: &str) -> Option<SecretMeta>{
let raw_metadata;
match db.get(path) {
Ok(Some(ivec)) => {
raw_metadata = ivec;
}
Err(e) => {
eprintln!("Error on retrieving metadata: {}", e);
return None;
}
Ok(None) => {
return None;
}
}
let as_str = String::from_utf8(raw_metadata.to_vec()).unwrap();
match deserialize_metadata_struct(&as_str) {
Ok(meta) => {
#[cfg(test)]
println!("got some metadata: {:?}", meta);
return Some(meta);
}
Err(e) => {
eprintln!("error on secret deserialization: {}", e);
return None;
}
}
}
// currently early version (copied from update_secret)
fn update_secret_meta(db: &Db, path: &str, mut meta: SecretMeta) {
match get_secretmeta(db, path) {
Some(meta) => {
// case secret found. TODO save it somewhere for versioning
#[cfg(test)]
print!("something was found. new version {:?} \n", meta)
}
None => {
}
}
match serialize_metadata_json(&meta) {
Ok(meta_json) => {
#[cfg(test)]
println!("String: {:?}", meta_json.clone());
let as_ivec = sled::IVec::from(meta_json.into_bytes()); // maybe outsource this in a fn later
#[cfg(test)]
println!("ivec: {:?}", as_ivec);
match db.insert(path, as_ivec) {
Ok(_) => println!("Metadata inserted"),
Err(e) => eprintln!("Failed to insert meta: {}", e),
}
}
Err(e) => eprintln!("Failed to serialize meta: {}", e),
}
}
/// 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
/// hard delete secret at path
fn delete_secret(db: &Db, path: &str) { fn delete_secret(db: &Db, path: &str) {
let rem = db.remove(path); let rem = db.remove(path);
} }