added database stuff

added clap arguments
added the gen_or_get_key func in lib
git ignore for .env
migrations
This commit is contained in:
2026-07-13 17:41:29 -05:00
parent 04c57f15f8
commit c64ed1be4e
15 changed files with 527 additions and 5 deletions
+12 -2
View File
@@ -7,8 +7,18 @@ description = "An opensource secrets management and distribution platform"
license = "GLP-3.0"
[dependencies]
tokio = { version = "1.52.3", features = ["full"] }
diesel = { version = "2.2.0", features = [
"sqlite",
"returning_clauses_for_sqlite_3_35",
"chrono",
] }
clap = { version = "4.6.1", features = ["derive", "cargo"] }
tokio = { version = "1.52.3", features = ["full"] }
crypto = { path = "../crypto" }
git-version = "0.3"
keyring = "4.1.4"
colored = "3.1.1"
git-version = "0.3"
chrono = "0.4.45"
dotenvy = "0.15"
uuid = "1.23.5"
hex = "0.4"
+9
View File
@@ -0,0 +1,9 @@
# For documentation on how to configure this file,
# see https://diesel.rs/guides/configuring-diesel-cli
[print_schema]
file = "src/db/schema.rs"
custom_type_derives = ["diesel::query_builder::QueryId", "Clone"]
[migrations_directory]
dir = "migrations"
Binary file not shown.
View File
View File
@@ -0,0 +1,2 @@
DROP TABLE IF EXISTS secrets;
DROP TABLE IF EXISTS projects;
@@ -0,0 +1,19 @@
CREATE TABLE projects (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE secrets (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
project_id TEXT NOT NULL,
config TEXT NOT NULL,
secret BLOB NOT NULL,
nonce BLOB NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE,
UNIQUE (project_id, config, name)
);
+14
View File
@@ -0,0 +1,14 @@
use diesel::prelude::*;
use dotenvy::dotenv;
use std::env;
pub mod models;
pub mod schema;
pub fn establish_connection() -> SqliteConnection {
dotenv().ok();
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
SqliteConnection::establish(&database_url)
.unwrap_or_else(|_| panic!("Error connecting to {}", database_url))
}
+25
View File
@@ -0,0 +1,25 @@
use crate::db::schema::{projects, secrets};
use chrono::NaiveDateTime;
use diesel::prelude::*;
#[derive(Debug, Queryable, Selectable)]
#[diesel(table_name = projects)]
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
pub struct Project {
pub id: String,
pub name: String,
pub created_at: NaiveDateTime,
}
#[derive(Debug, Queryable, Selectable)]
#[diesel(table_name = secrets)]
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
pub struct Secret {
pub id: String,
pub name: String,
pub project_id: String,
pub config: String,
pub secret: Vec<u8>,
pub nonce: Vec<u8>,
pub created_at: NaiveDateTime,
}
+25
View File
@@ -0,0 +1,25 @@
// @generated automatically by Diesel CLI.
diesel::table! {
projects (id) {
id -> Text,
name -> Text,
created_at -> Timestamp,
}
}
diesel::table! {
secrets (id) {
id -> Text,
name -> Text,
project_id -> Text,
config -> Text,
secret -> Binary,
nonce -> Binary,
created_at -> Timestamp,
}
}
diesel::joinable!(secrets -> projects (project_id));
diesel::allow_tables_to_appear_in_same_query!(projects, secrets,);
+39
View File
@@ -1,4 +1,7 @@
use clap::{Args, Parser, Subcommand};
use keyring::Entry;
use std::error::Error;
mod db;
#[derive(Parser)]
#[clap(
@@ -54,3 +57,39 @@ pub enum ConfigCommands {
Create { project: String, name: String },
Delete { project: String, name: String },
}
pub fn gen_or_get_key() -> Result<crypto::Key, Box<dyn Error>> {
let entry = Entry::new("harbor", "encryption-key")?;
match entry.get_password() {
Ok(hex_string) => {
let key_bytes = hex::decode(hex_string)?;
if key_bytes.len() != 32 {
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)
} else {
Err(Box::new(err))
}
}
}
}
fn is_key_not_found(err: &keyring::Error) -> bool {
matches!(err, keyring::Error::NoEntry)
}
+5 -2
View File
@@ -1,11 +1,14 @@
use chacha20poly1305::{
ChaCha20Poly1305, Key, Nonce,
ChaCha20Poly1305,
aead::{Aead, Generate, KeyInit},
};
type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
mod helper {
pub type Key = chacha20poly1305::Key;
pub type Nonce = chacha20poly1305::Nonce;
pub mod helper {
use super::{Generate, Key, Nonce};
pub fn gen_nonce() -> Nonce {
Nonce::generate()