generated from pure_sagacity/rust-starter
apparently the gen_or_get_key logic is for string only keys
changed that and also added an implementation for the trait
This commit is contained in:
Generated
+7
@@ -245,6 +245,12 @@ version = "1.5.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
|
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.22.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.13.0"
|
version = "2.13.0"
|
||||||
@@ -436,6 +442,7 @@ checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
|
|||||||
name = "cli"
|
name = "cli"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"base64",
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
"colored",
|
"colored",
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ tokio = { version = "1.52.3", features = ["full"] }
|
|||||||
crypto = { path = "../crypto" }
|
crypto = { path = "../crypto" }
|
||||||
keyring = "4.1.4"
|
keyring = "4.1.4"
|
||||||
colored = "3.1.1"
|
colored = "3.1.1"
|
||||||
|
base64 = "0.22.1"
|
||||||
chrono = "0.4.45"
|
chrono = "0.4.45"
|
||||||
dotenvy = "0.15"
|
dotenvy = "0.15"
|
||||||
uuid = "1.23.5"
|
uuid = "1.23.5"
|
||||||
|
|||||||
+18
-27
@@ -1,8 +1,10 @@
|
|||||||
|
use base64::{Engine, engine::general_purpose::STANDARD};
|
||||||
use clap::{Args, Parser, Subcommand};
|
use clap::{Args, Parser, Subcommand};
|
||||||
|
use crypto::helper::gen_key;
|
||||||
use keyring::Entry;
|
use keyring::Entry;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
mod db;
|
mod db;
|
||||||
|
mod store;
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[clap(
|
#[clap(
|
||||||
name = "Harbor",
|
name = "Harbor",
|
||||||
@@ -58,38 +60,27 @@ pub enum ConfigCommands {
|
|||||||
Delete { project: String, name: String },
|
Delete { project: String, name: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_or_get_key() -> Result<crypto::Key, Box<dyn Error>> {
|
fn gen_or_get_key() -> Result<crypto::Key, Box<dyn Error>> {
|
||||||
let entry = Entry::new("harbor", "encryption-key")?;
|
let entry = Entry::new("harbor", "encryption-key")?;
|
||||||
|
|
||||||
match entry.get_password() {
|
match entry.get_password() {
|
||||||
Ok(hex_string) => {
|
Ok(encoded) => {
|
||||||
let key_bytes = hex::decode(hex_string)?;
|
let bytes = STANDARD.decode(encoded)?;
|
||||||
|
|
||||||
if key_bytes.len() != 32 {
|
let key = crypto::helper::key_from(bytes)?;
|
||||||
return Err("Retrieved key length is invalid (must be 32 bytes)".into());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(key_bytes
|
|
||||||
.as_slice()
|
|
||||||
.try_into()
|
|
||||||
.map_err(|_| "Invalid key length")?)
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(err) => {
|
|
||||||
if is_key_not_found(&err) {
|
|
||||||
let key = crypto::helper::gen_key();
|
|
||||||
|
|
||||||
let hex_string = hex::encode(key.as_slice());
|
|
||||||
entry.set_password(&hex_string)?;
|
|
||||||
|
|
||||||
Ok(key)
|
Ok(key)
|
||||||
} else {
|
|
||||||
Err(Box::new(err))
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_key_not_found(err: &keyring::Error) -> bool {
|
Err(keyring::Error::NoEntry) => {
|
||||||
matches!(err, keyring::Error::NoEntry)
|
let key = gen_key();
|
||||||
|
|
||||||
|
let encoded = STANDARD.encode(key);
|
||||||
|
entry.set_password(&encoded)?;
|
||||||
|
|
||||||
|
Ok(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(err) => Err(Box::new(err)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {}
|
||||||
@@ -9,7 +9,7 @@ pub type Key = chacha20poly1305::Key;
|
|||||||
pub type Nonce = chacha20poly1305::Nonce;
|
pub type Nonce = chacha20poly1305::Nonce;
|
||||||
|
|
||||||
pub mod helper {
|
pub mod helper {
|
||||||
use super::{Generate, Key, Nonce};
|
use super::{Generate, Key, Nonce, Result};
|
||||||
pub fn gen_nonce() -> Nonce {
|
pub fn gen_nonce() -> Nonce {
|
||||||
Nonce::generate()
|
Nonce::generate()
|
||||||
}
|
}
|
||||||
@@ -17,6 +17,14 @@ pub mod helper {
|
|||||||
pub fn gen_key() -> Key {
|
pub fn gen_key() -> Key {
|
||||||
Key::generate()
|
Key::generate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn key_from(bytes: Vec<u8>) -> Result<Key> {
|
||||||
|
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<u8>) -> Result<(Nonce, Vec<u8>)> {
|
pub fn encrypt(key: &Key, plaintext: Vec<u8>) -> Result<(Nonce, Vec<u8>)> {
|
||||||
|
|||||||
Reference in New Issue
Block a user