Public Access
feat: initial source commit
This commit is contained in:
+107
@@ -0,0 +1,107 @@
|
||||
mod config;
|
||||
mod db;
|
||||
mod models;
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
use argon2::{Argon2, PasswordHasher, password_hash::{SaltString, rand_core::OsRng}};
|
||||
use uuid::Uuid;
|
||||
use rand::Rng;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(name = "gateway-cli", about = "Action Gateway admin CLI")]
|
||||
struct Cli {
|
||||
#[command(subcommand)]
|
||||
command: Commands,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum Commands {
|
||||
/// Add a user
|
||||
AddUser {
|
||||
username: String,
|
||||
password: String,
|
||||
},
|
||||
/// List all users
|
||||
ListUsers,
|
||||
/// Remove a user
|
||||
RemoveUser {
|
||||
username: String,
|
||||
},
|
||||
/// Generate a new API key for the agent
|
||||
GenApiKey {
|
||||
#[arg(default_value = "agent")]
|
||||
label: String,
|
||||
},
|
||||
/// List API keys
|
||||
ListKeys,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let cli = Cli::parse();
|
||||
let config = config::Config::load();
|
||||
let conn = db::open(&config.database_path).expect("Failed to open database");
|
||||
|
||||
match cli.command {
|
||||
Commands::AddUser { username, password } => {
|
||||
let salt = SaltString::generate(&mut OsRng);
|
||||
let hash = Argon2::default()
|
||||
.hash_password(password.as_bytes(), &salt)
|
||||
.unwrap()
|
||||
.to_string();
|
||||
conn.execute(
|
||||
"INSERT INTO users (id, username, password_hash) VALUES (?1, ?2, ?3)",
|
||||
[&Uuid::new_v4().to_string(), &username, &hash],
|
||||
).unwrap();
|
||||
println!("✅ User '{}' created.", username);
|
||||
}
|
||||
Commands::ListUsers => {
|
||||
let mut stmt = conn.prepare("SELECT username, created_at FROM users ORDER BY created_at").unwrap();
|
||||
let users: Vec<(String, String)> = stmt.query_map([], |row| Ok((row.get(0)?, row.get(1)?))).unwrap()
|
||||
.filter_map(|r| r.ok()).collect();
|
||||
if users.is_empty() {
|
||||
println!("No users.");
|
||||
} else {
|
||||
println!("{:<20} {}", "Username", "Created");
|
||||
println!("{}", "-".repeat(40));
|
||||
for (u, c) in users { println!("{:<20} {}", u, c); }
|
||||
}
|
||||
}
|
||||
Commands::RemoveUser { username } => {
|
||||
let n = conn.execute("DELETE FROM users WHERE username = ?1", [&username]).unwrap();
|
||||
if n > 0 { println!("✅ User '{}' removed.", username); }
|
||||
else { println!("❌ User '{}' not found.", username); }
|
||||
}
|
||||
Commands::GenApiKey { label } => {
|
||||
// Generate random key
|
||||
let key: String = rand::thread_rng()
|
||||
.sample_iter(&rand::distributions::Alphanumeric)
|
||||
.take(48)
|
||||
.map(char::from)
|
||||
.collect();
|
||||
let salt = SaltString::generate(&mut OsRng);
|
||||
let hash = Argon2::default()
|
||||
.hash_password(key.as_bytes(), &salt)
|
||||
.unwrap()
|
||||
.to_string();
|
||||
conn.execute(
|
||||
"INSERT INTO api_keys (id, key_hash, label) VALUES (?1, ?2, ?3)",
|
||||
[&Uuid::new_v4().to_string(), &hash, &label],
|
||||
).unwrap();
|
||||
println!("✅ API key generated for '{}':", label);
|
||||
println!("\n {}\n", key);
|
||||
println!("Store this key securely — it won't be shown again.");
|
||||
}
|
||||
Commands::ListKeys => {
|
||||
let mut stmt = conn.prepare("SELECT label, created_at FROM api_keys ORDER BY created_at").unwrap();
|
||||
let keys: Vec<(String, String)> = stmt.query_map([], |row| Ok((row.get(0)?, row.get(1)?))).unwrap()
|
||||
.filter_map(|r| r.ok()).collect();
|
||||
if keys.is_empty() {
|
||||
println!("No API keys.");
|
||||
} else {
|
||||
println!("{:<20} {}", "Label", "Created");
|
||||
println!("{}", "-".repeat(40));
|
||||
for (l, c) in keys { println!("{:<20} {}", l, c); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user