From 29033259dfa409691313685f656694099189b53a Mon Sep 17 00:00:00 2001 From: Maaz Khokhar Date: Mon, 13 Jul 2026 19:19:29 -0500 Subject: [PATCH] apparently the gen_or_get_key logic is for string only keys changed that and also added an implementation for the trait --- Cargo.lock | 7 +++++++ crates/cli/Cargo.toml | 1 + crates/cli/src/lib.rs | 39 ++++++++++++++----------------------- crates/cli/src/store/mod.rs | 7 +++++++ crates/crypto/src/lib.rs | 10 +++++++++- 5 files changed, 39 insertions(+), 25 deletions(-) create mode 100644 crates/cli/src/store/mod.rs diff --git a/Cargo.lock b/Cargo.lock index ad26824..b314bc2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -245,6 +245,12 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "bitflags" version = "2.13.0" @@ -436,6 +442,7 @@ checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" name = "cli" version = "1.0.0" dependencies = [ + "base64", "chrono", "clap", "colored", diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index c0a8e53..3035f88 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -17,6 +17,7 @@ tokio = { version = "1.52.3", features = ["full"] } crypto = { path = "../crypto" } keyring = "4.1.4" colored = "3.1.1" +base64 = "0.22.1" chrono = "0.4.45" dotenvy = "0.15" uuid = "1.23.5" diff --git a/crates/cli/src/lib.rs b/crates/cli/src/lib.rs index 545624f..5e23d93 100644 --- a/crates/cli/src/lib.rs +++ b/crates/cli/src/lib.rs @@ -1,8 +1,10 @@ +use base64::{Engine, engine::general_purpose::STANDARD}; use clap::{Args, Parser, Subcommand}; +use crypto::helper::gen_key; use keyring::Entry; use std::error::Error; mod db; - +mod store; #[derive(Parser)] #[clap( name = "Harbor", @@ -58,38 +60,27 @@ pub enum ConfigCommands { Delete { project: String, name: String }, } -pub fn gen_or_get_key() -> Result> { +fn gen_or_get_key() -> Result> { let entry = Entry::new("harbor", "encryption-key")?; match entry.get_password() { - Ok(hex_string) => { - let key_bytes = hex::decode(hex_string)?; + Ok(encoded) => { + let bytes = STANDARD.decode(encoded)?; - if key_bytes.len() != 32 { - return Err("Retrieved key length is invalid (must be 32 bytes)".into()); - } + let key = crypto::helper::key_from(bytes)?; - Ok(key_bytes - .as_slice() - .try_into() - .map_err(|_| "Invalid key length")?) + Ok(key) } - Err(err) => { - if is_key_not_found(&err) { - let key = crypto::helper::gen_key(); + Err(keyring::Error::NoEntry) => { + let key = gen_key(); - let hex_string = hex::encode(key.as_slice()); - entry.set_password(&hex_string)?; + let encoded = STANDARD.encode(key); + entry.set_password(&encoded)?; - Ok(key) - } else { - Err(Box::new(err)) - } + Ok(key) } + + Err(err) => Err(Box::new(err)), } } - -fn is_key_not_found(err: &keyring::Error) -> bool { - matches!(err, keyring::Error::NoEntry) -} diff --git a/crates/cli/src/store/mod.rs b/crates/cli/src/store/mod.rs new file mode 100644 index 0000000..8cf3d82 --- /dev/null +++ b/crates/cli/src/store/mod.rs @@ -0,0 +1,7 @@ +// This trait will replace the current implementation. +// Right now, the implementation is locked on only SQLite. +// With this trait, we can implement other savers like Postgres, MySQL, etc. +// Or even third party services like Hashicorp Vault, AWS Secrets Manager, etc. + +// For now, I'll just get an MVP in place. +pub trait Store {} diff --git a/crates/crypto/src/lib.rs b/crates/crypto/src/lib.rs index 79394fe..e192cd2 100644 --- a/crates/crypto/src/lib.rs +++ b/crates/crypto/src/lib.rs @@ -9,7 +9,7 @@ pub type Key = chacha20poly1305::Key; pub type Nonce = chacha20poly1305::Nonce; pub mod helper { - use super::{Generate, Key, Nonce}; + use super::{Generate, Key, Nonce, Result}; pub fn gen_nonce() -> Nonce { Nonce::generate() } @@ -17,6 +17,14 @@ pub mod helper { pub fn gen_key() -> Key { Key::generate() } + + pub fn key_from(bytes: Vec) -> Result { + let array: [u8; 32] = bytes + .try_into() + .map_err(|_| "key must be exactly 32 bytes".to_string())?; + + Ok(Key::from(array)) + } } pub fn encrypt(key: &Key, plaintext: Vec) -> Result<(Nonce, Vec)> {