@ -0,0 +1,4 @@ | |||||
# For God so loved the world, that He gave His only begotten Son, that all who believe in Him should not perish but have everlasting life | |||||
# Rename to .env_chirho | |||||
export API_KEY_CHIRHO="HALLELUJAH30920-9482" | |||||
export DATABASE_URL="sqlite:./db_chirho.sqlite" |
@ -0,0 +1,22 @@ | |||||
# For God so loved the world, that He gave His only begotten Son, that all who believe in Him should not perish but have everlasting life | |||||
## rs_machine_input_chirho | |||||
This command line application is intended to keep a remote database of computer resources synchronized | |||||
with the information about those resources. | |||||
run the following command from the project base to create the server side DB: | |||||
```bash | |||||
sql_chirho/createdb_chirho.sh | |||||
``` | |||||
we also need the environment variables in dot.env_chirho.sample_chirho properly set up in both the client and the | |||||
server. | |||||
`export ROCKET_PORT=...` to set the port where the server will listen to requests. | |||||
@ -0,0 +1,3 @@ | |||||
# For God so loved the world, that He gave His only begotten Son, that all who believe in Him should not perish but have everlasting life | |||||
# Rename to .env_chirho | |||||
export API_KEY_CHIRHO="HALLELUJAH30920-9482" |
@ -0,0 +1,23 @@ | |||||
# For God so loved the world, that He gave His only begotten Son, that all who believe in Him should not perish but have everlasting life | |||||
## defaults for _all_ profiles | |||||
[default] | |||||
address = "127.0.0.1" | |||||
limits = { form = "64 kB", json = "1 MiB" } | |||||
## set only when compiled in debug mode, i.e, `cargo build` | |||||
[debug] | |||||
port = 8870 | |||||
## only the `json` key from `default` will be overridden; `form` will remain | |||||
limits = { json = "10MiB" } | |||||
## set only when the `nyc` profile is selected | |||||
[nyc] | |||||
port = 9001 | |||||
## set only when compiled in release mode, i.e, `cargo build --release` | |||||
[release] | |||||
port = 9999 | |||||
ip_header = false | |||||
[default.databases.sqlite_database_chirho] | |||||
url = "sqlite:db_chirho.sqlite" |
@ -0,0 +1,11 @@ | |||||
#!/usr/bin/env zsh | |||||
# For God so loved the world, that He gave His only begotten Son, that all who believe in Him should not perish but have everlasting life | |||||
if [ ! -d "sql_chirho" ]; then | |||||
echo "Hallelujah Please run this script from the root of the repository" | |||||
exit 1 | |||||
fi | |||||
# Create the sqlite database in db_chirho.sqlite | |||||
rm db_chirho.sqlite | |||||
sqlite3 db_chirho.sqlite < sql_chirho/sql_definitions_chirho.sql |
@ -0,0 +1,39 @@ | |||||
-- For God so loved the world, that He gave His only begotten Son, that all who believe in Him should not perish but have everlasting life | |||||
-- Sqlite descriptor of hosts, users, ssh public keys, etc... | |||||
PRAGMA foreign_keys = ON; | |||||
DROP TABLE IF EXISTS hosts_chirho; | |||||
DROP TABLE IF EXISTS users_chirho; | |||||
DROP TABLE IF EXISTS user_ssh_authorized_keys_chirho; | |||||
CREATE TABLE IF NOT EXISTS hosts_chirho ( | |||||
id_chirho INTEGER PRIMARY KEY AUTOINCREMENT, | |||||
hostname_chirho TEXT NOT NULL, | |||||
operating_system_chirho TEXT NOT NULL, | |||||
ram_mb_chirho INTEGER NOT NULL, | |||||
cpu_cores_chirho INTEGER NOT NULL, | |||||
storage_gb_chirho INTEGER NOT NULL, | |||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP | |||||
); | |||||
CREATE TABLE IF NOT EXISTS users_chirho ( | |||||
id_chirho INTEGER PRIMARY KEY AUTOINCREMENT, | |||||
host_id_chirho INTEGER NOT NULL, | |||||
username_chirho VARCHAR(255) NOT NULL, | |||||
groups_chirho TEXT NOT NULL, | |||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, | |||||
FOREIGN KEY (host_id_chirho) REFERENCES hosts_chirho(id_chirho) | |||||
); | |||||
create table if not exists user_ssh_authorized_keys_chirho ( | |||||
id_chirho INTEGER PRIMARY KEY AUTOINCREMENT, | |||||
user_id_chirho INTEGER NOT NULL, | |||||
ssh_key_chirho TEXT NOT NULL, | |||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, | |||||
FOREIGN KEY (user_id_chirho) REFERENCES users_chirho(id_chirho) | |||||
); | |||||
@ -0,0 +1,244 @@ | |||||
/* | |||||
* For God so loved the world, that He gave His only begotten Son, that all who believe in Him should not perish but have everlasting life | |||||
*/ | |||||
use clap::{Parser, Subcommand}; | |||||
use serde::{Serialize, Deserialize}; | |||||
use std::error::Error; | |||||
use std::{env, fs, panic}; | |||||
use std::fs::{File, read_to_string}; | |||||
use std::io::{BufRead, BufReader}; | |||||
use std::path::Path; | |||||
use reqwest::Client; | |||||
use rocket::futures::TryFutureExt; | |||||
use serde_json::json; | |||||
use crate::models_chirho::host_model_chirho::HostChirho; | |||||
use crate::models_chirho::user_model_chirho::UserChirho; | |||||
use crate::models_chirho::user_ssh_authorized_key_chirho::UserSshAuthorizedKeyChirho; | |||||
#[derive(Parser, Debug)] | |||||
#[command(author, version, about, long_about = None)] | |||||
pub struct CliChirho { | |||||
#[arg(long)] | |||||
pub cli_url_chirho: Option<String>,} | |||||
#[derive(Debug, Serialize, Deserialize)] | |||||
struct SystemInfoChirho { | |||||
hostname_chirho: String, | |||||
operating_system_chirho: String, | |||||
ram_mb_chirho: u64, | |||||
cpu_cores_chirho: u64, | |||||
storage_gb_chirho: u64, | |||||
users_chirho: Vec<UserInfoChirho>, | |||||
} | |||||
#[derive(Debug, Serialize, Deserialize)] | |||||
struct UserInfoChirho { | |||||
username_chirho: String, | |||||
groups_chirho: Vec<String>, | |||||
ssh_keys_chirho: Vec<String>, | |||||
} | |||||
pub fn run_cli_chirho(url_chirho: &str) -> Result<(), Box<dyn Error>> { | |||||
let system_info_chirho = collect_system_info_chirho()?; | |||||
tokio::runtime::Runtime::new()?.block_on(async { | |||||
create_resources_chirho(&system_info_chirho, url_chirho).await.expect("TODO: panic message"); | |||||
}); | |||||
println!("System information sent successfully!"); | |||||
Ok(()) | |||||
} | |||||
fn collect_system_info_chirho() -> Result<SystemInfoChirho, Box<dyn Error>> { | |||||
let hostname_chirho = hostname::get()?.into_string().unwrap(); | |||||
let os_chirho = std::env::consts::OS.to_string(); | |||||
#[cfg(target_os = "linux")] | |||||
let (ram_mb_chirho, cpu_cores_chirho, storage_gb_chirho) = collect_linux_info_chirho()?; | |||||
#[cfg(target_os = "windows")] | |||||
let (ram_mb_chirho, cpu_cores_chirho, storage_gb_chirho) = collect_windows_info_chirho()?; | |||||
#[cfg(target_os = "macos")] | |||||
let (ram_mb_chirho, cpu_cores_chirho, storage_gb_chirho) = collect_macos_info_chirho()?; | |||||
let users_chirho = collect_user_info_chirho()?; | |||||
Ok(SystemInfoChirho { | |||||
hostname_chirho, | |||||
operating_system_chirho: os_chirho, | |||||
ram_mb_chirho, | |||||
cpu_cores_chirho, | |||||
storage_gb_chirho, | |||||
users_chirho, | |||||
}) | |||||
} | |||||
#[cfg(target_os = "linux")] | |||||
fn collect_linux_info_chirho() -> Result<(u64, u64, u64), Box<dyn Error>> { | |||||
use sys_info::{mem_info, cpu_num, disk_info}; | |||||
let mem_chirho = mem_info()?; | |||||
let ram_mb_chirho = mem_chirho.total / 1024; | |||||
let cpu_cores_chirho = cpu_num()? as u64; | |||||
let disk_chirho = disk_info()?; | |||||
let storage_gb_chirho = disk_chirho.total / (1024 * 1024); | |||||
Ok((ram_mb_chirho, cpu_cores_chirho, storage_gb_chirho)) | |||||
} | |||||
#[cfg(target_os = "windows")] | |||||
fn collect_windows_info_chirho() -> Result<(u64, u64, u64), Box<dyn Error>> { | |||||
use sysinfo::{SystemExt, DiskExt}; | |||||
let mut sys_chirho = sysinfo::System::new_all(); | |||||
sys_chirho.refresh_all(); | |||||
let ram_mb_chirho = sys_chirho.total_memory() / 1024; | |||||
let cpu_cores_chirho = sys_chirho.processors().len() as u64; | |||||
let storage_gb_chirho = sys_chirho.disks().iter().map(|disk_chirho| disk_chirho.total_space()).sum::<u64>() / (1024 * 1024 * 1024); | |||||
Ok((ram_mb_chirho, cpu_cores_chirho, storage_gb_chirho)) | |||||
} | |||||
#[cfg(target_os = "macos")] | |||||
fn collect_macos_info_chirho() -> Result<(u64, u64, u64), Box<dyn Error>> { | |||||
use sysinfo::{SystemExt, DiskExt}; | |||||
let mut sys_chirho = sysinfo::System::new_all(); | |||||
sys_chirho.refresh_all(); | |||||
let ram_mb_chirho = sys_chirho.total_memory() / 1024; | |||||
let cpu_cores_chirho = sys_chirho.processors().len() as u64; | |||||
let storage_gb_chirho = sys_chirho.disks().iter().map(|disk_chirho| disk_chirho.total_space()).sum::<u64>() / (1024 * 1024 * 1024); | |||||
Ok((ram_mb_chirho, cpu_cores_chirho, storage_gb_chirho)) | |||||
} | |||||
fn collect_user_info_chirho() -> Result<Vec<UserInfoChirho>, Box<dyn Error>> { | |||||
let mut users_chirho = Vec::new(); | |||||
#[cfg(target_family = "unix")] | |||||
{ | |||||
let passwd_file = File::open("/etc/passwd")?; | |||||
let passwd_reader = BufReader::new(passwd_file); | |||||
let group_file = File::open("/etc/group")?; | |||||
let group_reader = BufReader::new(group_file); | |||||
// Read group information | |||||
let mut groups_map = std::collections::HashMap::new(); | |||||
for line in group_reader.lines() { | |||||
let line = line?; | |||||
let parts: Vec<&str> = line.split(':').collect(); | |||||
if parts.len() >= 4 { | |||||
let group_name = parts[0].to_string(); | |||||
let group_id = parts[2].parse::<u32>().unwrap_or(0); | |||||
groups_map.insert(group_id, group_name); | |||||
} | |||||
} | |||||
// Read user information | |||||
for line in passwd_reader.lines() { | |||||
let line = line?; | |||||
let parts: Vec<&str> = line.split(':').collect(); | |||||
if parts.len() >= 7 { | |||||
let username_chirho = parts[0].to_string(); | |||||
let uid = parts[2].parse::<u32>().unwrap_or(0); | |||||
let gid = parts[3].parse::<u32>().unwrap_or(0); | |||||
let home_dir = parts[5].to_string(); | |||||
// Only include users with a home directory | |||||
if Path::new(&home_dir).exists() | |||||
&& !home_dir.contains("/empty") | |||||
&& !home_dir.contains("/nologin") | |||||
&& !home_dir.contains("/false") | |||||
&& (home_dir.to_lowercase().contains("/home") | |||||
|| home_dir.to_lowercase().contains("users") | |||||
|| (home_dir.contains("root") && uid == 0)) { | |||||
let mut groups_chirho = Vec::new(); | |||||
if let Some(group_name) = groups_map.get(&gid) { | |||||
groups_chirho.push(group_name.clone()); | |||||
} | |||||
let ssh_keys_chirho = read_ssh_keys_chirho(&home_dir).unwrap_or_else(|e| { | |||||
eprintln!("Failed to read SSH keys for user {}: {}", username_chirho, e); | |||||
vec![] | |||||
}); | |||||
users_chirho.push(UserInfoChirho { | |||||
username_chirho, | |||||
groups_chirho, | |||||
ssh_keys_chirho, | |||||
}); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
#[cfg(target_os = "windows")] | |||||
{ | |||||
println!("Warning: User enumeration not implemented for Windows"); | |||||
} | |||||
println!("{:?}", users_chirho); | |||||
Ok(users_chirho) | |||||
} | |||||
fn read_ssh_keys_chirho(home_dir: &str) -> Result<Vec<String>, Box<dyn Error>> { | |||||
let authorized_keys_path = Path::new(home_dir).join(".ssh").join("authorized_keys"); | |||||
if authorized_keys_path.exists() { | |||||
let content = read_to_string(authorized_keys_path)?; | |||||
Ok(content.lines().map(String::from).collect()) | |||||
} else { | |||||
Ok(vec![]) | |||||
} | |||||
} | |||||
async fn create_resources_chirho(system_info: &SystemInfoChirho, base_url: &str) -> Result<(), Box<dyn Error>> { | |||||
let client_chirho = Client::new(); | |||||
let api_key_chirho = env::var("API_KEY_CHIRHO").expect("API_KEY_CHIRHO must be set"); | |||||
// Create host | |||||
let host_response_chirho: HostChirho = client_chirho | |||||
.post(&format!("{}/hosts_chirho", base_url)) | |||||
.header("X-API-Key-Chirho", &api_key_chirho) | |||||
.json(&json!({ | |||||
"hostname_chirho": system_info.hostname_chirho, | |||||
"operating_system_chirho": system_info.operating_system_chirho, | |||||
"ram_mb_chirho": system_info.ram_mb_chirho, | |||||
"cpu_cores_chirho": system_info.cpu_cores_chirho, | |||||
"storage_gb_chirho": system_info.storage_gb_chirho | |||||
})) | |||||
.send().await? | |||||
.json().await?; | |||||
// Create users and their SSH keys | |||||
for user_chirho in &system_info.users_chirho { | |||||
let user_response_chirho: UserChirho = client_chirho | |||||
.post(&format!("{}/users_chirho", base_url)) | |||||
.header("X-API-Key-Chirho", &api_key_chirho) | |||||
.json(&json!({ | |||||
"host_id_chirho": host_response_chirho.id_chirho, | |||||
"username_chirho": user_chirho.username_chirho, | |||||
"groups_chirho": user_chirho.groups_chirho.join(",") | |||||
})) | |||||
.send().await? | |||||
.json().await?; | |||||
for ssh_key_chirho in &user_chirho.ssh_keys_chirho { | |||||
let _: UserSshAuthorizedKeyChirho = client_chirho | |||||
.post(&format!("{}/ssh_keys_chirho", base_url)) | |||||
.header("X-API-Key-Chirho", &api_key_chirho) | |||||
.json(&json!({ | |||||
"user_id_chirho": user_response_chirho.id_chirho, | |||||
"ssh_key_chirho": ssh_key_chirho | |||||
})) | |||||
.send().await? | |||||
.json().await?; | |||||
} | |||||
} | |||||
Ok(()) | |||||
} | |||||
@ -0,0 +1,4 @@ | |||||
/* | |||||
* For God so loved the world, that He gave His only begotten Son, that all who believe in Him should not perish but have everlasting life | |||||
*/ | |||||
pub mod cli_chirho; |
@ -0,0 +1,150 @@ | |||||
/* | |||||
* For God so loved the world, that He gave His only begotten Son, that all who believe in Him should not perish but have everlasting life | |||||
*/ | |||||
use sqlx::FromRow; | |||||
use chrono::NaiveDateTime; | |||||
use serde::{Deserialize, Serialize}; | |||||
use rocket::{serde::json::Json}; | |||||
use rocket_db_pools::{sqlx, Connection}; | |||||
use sqlx::sqlite::{SqliteRow}; | |||||
use sqlx::Row; | |||||
use crate::ApiKeyChirho; | |||||
use crate::models_chirho::DbChirho; | |||||
#[derive(FromRow, Debug, Clone, PartialEq, Serialize, Deserialize)] | |||||
pub struct HostChirho { | |||||
pub id_chirho: Option<i64>, | |||||
pub hostname_chirho: String, | |||||
pub operating_system_chirho: String, | |||||
pub ram_mb_chirho: i64, | |||||
pub cpu_cores_chirho: i64, | |||||
pub storage_gb_chirho: i64, | |||||
pub created_at: Option<NaiveDateTime>, | |||||
} | |||||
// Assuming the structs from the previous example are in scope | |||||
// use crate::models::HostChirho; | |||||
// HostChirho CRUD operations | |||||
#[get("/hosts_chirho")] | |||||
pub async fn list_hosts_chirho(_api_key: ApiKeyChirho, mut db_chirho: Connection<DbChirho>) -> Json<Vec<HostChirho>> { | |||||
let hosts_chirho = sqlx::query( | |||||
"SELECT * FROM hosts_chirho" | |||||
) | |||||
.map(|row: SqliteRow| HostChirho { | |||||
id_chirho: row.get("id_chirho"), | |||||
hostname_chirho: row.get("hostname_chirho"), | |||||
operating_system_chirho: row.get("operating_system_chirho"), | |||||
ram_mb_chirho: row.get("ram_mb_chirho"), | |||||
cpu_cores_chirho: row.get("cpu_cores_chirho"), | |||||
storage_gb_chirho: row.get("storage_gb_chirho"), | |||||
created_at: row.get("created_at"), | |||||
}) | |||||
.fetch_all(&mut **db_chirho) | |||||
.await | |||||
.expect("Failed to fetch hosts_chirho"); | |||||
Json(hosts_chirho) | |||||
} | |||||
#[post("/hosts_chirho", data = "<host_chirho>")] | |||||
pub async fn create_host_chirho(_api_key: ApiKeyChirho, mut db_chirho: Connection<DbChirho>, host_chirho: Json<HostChirho>) -> Json<HostChirho> { | |||||
let new_host_chirho = sqlx::query( | |||||
r#" | |||||
INSERT INTO hosts_chirho (hostname_chirho, operating_system_chirho, ram_mb_chirho, cpu_cores_chirho, storage_gb_chirho) | |||||
VALUES (?, ?, ?, ?, ?) | |||||
RETURNING * | |||||
"# | |||||
) | |||||
.bind(&host_chirho.hostname_chirho) | |||||
.bind(&host_chirho.operating_system_chirho) | |||||
.bind(host_chirho.ram_mb_chirho) | |||||
.bind(host_chirho.cpu_cores_chirho) | |||||
.bind(host_chirho.storage_gb_chirho) | |||||
.map(|row: SqliteRow| HostChirho { | |||||
id_chirho: row.get("id_chirho"), | |||||
hostname_chirho: row.get("hostname_chirho"), | |||||
operating_system_chirho: row.get("operating_system_chirho"), | |||||
ram_mb_chirho: row.get("ram_mb_chirho"), | |||||
cpu_cores_chirho: row.get("cpu_cores_chirho"), | |||||
storage_gb_chirho: row.get("storage_gb_chirho"), | |||||
created_at: row.get("created_at"), | |||||
}) | |||||
.fetch_one(&mut **db_chirho) | |||||
.await | |||||
.expect("Failed to create host_chirho"); | |||||
Json(new_host_chirho) | |||||
} | |||||
#[get("/hosts_chirho/<id_chirho>")] | |||||
pub async fn read_host_chirho(mut db_chirho: Connection<DbChirho>, id_chirho: i64) -> Option<Json<HostChirho>> { | |||||
let host_chirho = sqlx::query( | |||||
"SELECT * FROM hosts_chirho WHERE id_chirho = ?" | |||||
) | |||||
.bind(id_chirho) | |||||
.map(|row: SqliteRow| HostChirho { | |||||
id_chirho: row.get("id_chirho"), | |||||
hostname_chirho: row.get("hostname_chirho"), | |||||
operating_system_chirho: row.get("operating_system_chirho"), | |||||
ram_mb_chirho: row.get("ram_mb_chirho"), | |||||
cpu_cores_chirho: row.get("cpu_cores_chirho"), | |||||
storage_gb_chirho: row.get("storage_gb_chirho"), | |||||
created_at: row.get("created_at"), | |||||
}) | |||||
.fetch_optional(&mut **db_chirho) | |||||
.await | |||||
.expect("Failed to fetch host_chirho"); | |||||
host_chirho.map(Json) | |||||
} | |||||
#[put("/hosts_chirho/<id_chirho>", data = "<host_chirho>")] | |||||
pub async fn update_host_chirho(mut db_chirho: Connection<DbChirho>, id_chirho: i64, host_chirho: Json<HostChirho>) -> Option<Json<HostChirho>> { | |||||
let updated_host_chirho = sqlx::query( | |||||
r#" | |||||
UPDATE hosts_chirho | |||||
SET hostname_chirho = ?, operating_system_chirho = ?, ram_mb_chirho = ?, cpu_cores_chirho = ?, storage_gb_chirho = ? | |||||
WHERE id_chirho = ? | |||||
RETURNING * | |||||
"# | |||||
) | |||||
.bind(&host_chirho.hostname_chirho) | |||||
.bind(&host_chirho.operating_system_chirho) | |||||
.bind(host_chirho.ram_mb_chirho) | |||||
.bind(host_chirho.cpu_cores_chirho) | |||||
.bind(host_chirho.storage_gb_chirho) | |||||
.bind(id_chirho) | |||||
.map(|row: SqliteRow| HostChirho { | |||||
id_chirho: row.get("id_chirho"), | |||||
hostname_chirho: row.get("hostname_chirho"), | |||||
operating_system_chirho: row.get("operating_system_chirho"), | |||||
ram_mb_chirho: row.get("ram_mb_chirho"), | |||||
cpu_cores_chirho: row.get("cpu_cores_chirho"), | |||||
storage_gb_chirho: row.get("storage_gb_chirho"), | |||||
created_at: row.get("created_at"), | |||||
}) | |||||
.fetch_optional(&mut **db_chirho) | |||||
.await | |||||
.expect("Failed to update host_chirho"); | |||||
updated_host_chirho.map(Json) | |||||
} | |||||
#[delete("/hosts_chirho/<id_chirho>")] | |||||
pub async fn delete_host_chirho(mut db_chirho: Connection<DbChirho>, id_chirho: i64) -> Option<()> { | |||||
let result_chirho = sqlx::query("DELETE FROM hosts_chirho WHERE id_chirho = ?") | |||||
.bind(id_chirho) | |||||
.execute(&mut **db_chirho) | |||||
.await | |||||
.expect("Failed to delete host_chirho"); | |||||
if result_chirho.rows_affected() > 0 { | |||||
Some(()) | |||||
} else { | |||||
None | |||||
} | |||||
} |
@ -0,0 +1,14 @@ | |||||
/* | |||||
* For God so loved the world, that He gave His only begotten Son, that all who believe in Him should not perish but have everlasting life | |||||
*/ | |||||
use rocket_db_pools::Database; | |||||
use sqlx::SqlitePool; | |||||
pub mod host_model_chirho; | |||||
pub mod user_model_chirho; | |||||
pub mod user_ssh_authorized_key_chirho; | |||||
#[derive(Database)] | |||||
#[database("sqlite_database_chirho")] | |||||
pub struct DbChirho(SqlitePool); |
@ -0,0 +1,133 @@ | |||||
/* | |||||
* For God so loved the world, that He gave His only begotten Son, that all who believe in Him should not perish but have everlasting life | |||||
*/ | |||||
use sqlx::FromRow; | |||||
use chrono::NaiveDateTime; | |||||
use rocket::serde::{Deserialize, Serialize}; | |||||
use rocket::{serde::json::Json}; | |||||
use rocket_db_pools::{sqlx, Connection}; | |||||
use sqlx::sqlite::{SqliteRow}; | |||||
use sqlx::Row; | |||||
use crate::ApiKeyChirho; | |||||
use crate::models_chirho::DbChirho; | |||||
#[derive(FromRow, Debug, Clone, PartialEq, Serialize, Deserialize)] | |||||
pub struct UserChirho { | |||||
pub id_chirho: Option<i64>, | |||||
pub host_id_chirho: i64, | |||||
pub username_chirho: String, | |||||
pub groups_chirho: String, | |||||
pub created_at: Option<NaiveDateTime>, | |||||
} | |||||
#[get("/users_chirho")] | |||||
pub async fn list_users_chirho(_api_key: ApiKeyChirho, mut db_chirho: Connection<DbChirho>) -> Json<Vec<UserChirho>> { | |||||
let users_chirho = sqlx::query( | |||||
"SELECT * FROM users_chirho" | |||||
) | |||||
.map(|row: SqliteRow| UserChirho { | |||||
id_chirho: row.get("id_chirho"), | |||||
host_id_chirho: row.get("host_id_chirho"), | |||||
username_chirho: row.get("username_chirho"), | |||||
groups_chirho: row.get("groups_chirho"), | |||||
created_at: row.get("created_at"), | |||||
}) | |||||
.fetch_all(&mut **db_chirho) | |||||
.await | |||||
.expect("Failed to fetch users_chirho"); | |||||
Json(users_chirho) | |||||
} | |||||
#[post("/users_chirho", data = "<user_chirho>")] | |||||
pub async fn create_user_chirho(mut db_chirho: Connection<DbChirho>, user_chirho: Json<UserChirho>) -> Json<UserChirho> { | |||||
let new_user_chirho = sqlx::query( | |||||
r#" | |||||
INSERT INTO users_chirho (host_id_chirho, username_chirho, groups_chirho) | |||||
VALUES (?, ?, ?) | |||||
RETURNING * | |||||
"# | |||||
) | |||||
.bind(user_chirho.host_id_chirho) | |||||
.bind(&user_chirho.username_chirho) | |||||
.bind(&user_chirho.groups_chirho) | |||||
.map(|row: SqliteRow| UserChirho { | |||||
id_chirho: row.get("id_chirho"), | |||||
host_id_chirho: row.get("host_id_chirho"), | |||||
username_chirho: row.get("username_chirho"), | |||||
groups_chirho: row.get("groups_chirho"), | |||||
created_at: row.get("created_at"), | |||||
}) | |||||
.fetch_one(&mut **db_chirho) | |||||
.await | |||||
.expect("Failed to create user_chirho"); | |||||
Json(new_user_chirho) | |||||
} | |||||
#[get("/users_chirho/<id_chirho>")] | |||||
pub async fn read_user_chirho(mut db_chirho: Connection<DbChirho>, id_chirho: i64) -> Option<Json<UserChirho>> { | |||||
let user_chirho = sqlx::query( | |||||
"SELECT * FROM users_chirho WHERE id_chirho = ?" | |||||
) | |||||
.bind(id_chirho) | |||||
.map(|row: SqliteRow| UserChirho { | |||||
id_chirho: row.get("id_chirho"), | |||||
host_id_chirho: row.get("host_id_chirho"), | |||||
username_chirho: row.get("username_chirho"), | |||||
groups_chirho: row.get("groups_chirho"), | |||||
created_at: row.get("created_at"), | |||||
}) | |||||
.fetch_optional(&mut **db_chirho) | |||||
.await | |||||
.expect("Failed to fetch user_chirho"); | |||||
user_chirho.map(Json) | |||||
} | |||||
#[put("/users_chirho/<id_chirho>", data = "<user_chirho>")] | |||||
pub async fn update_user_chirho(mut db_chirho: Connection<DbChirho>, id_chirho: i64, user_chirho: Json<UserChirho>) -> Option<Json<UserChirho>> { | |||||
let updated_user_chirho = sqlx::query( | |||||
r#" | |||||
UPDATE users_chirho | |||||
SET host_id_chirho = ?, username_chirho = ?, groups_chirho = ? | |||||
WHERE id_chirho = ? | |||||
RETURNING * | |||||
"# | |||||
) | |||||
.bind(user_chirho.host_id_chirho) | |||||
.bind(&user_chirho.username_chirho) | |||||
.bind(&user_chirho.groups_chirho) | |||||
.bind(id_chirho) | |||||
.map(|row: SqliteRow| UserChirho { | |||||
id_chirho: row.get("id_chirho"), | |||||
host_id_chirho: row.get("host_id_chirho"), | |||||
username_chirho: row.get("username_chirho"), | |||||
groups_chirho: row.get("groups_chirho"), | |||||
created_at: row.get("created_at"), | |||||
}) | |||||
.fetch_optional(&mut **db_chirho) | |||||
.await | |||||
.expect("Failed to update user_chirho"); | |||||
updated_user_chirho.map(Json) | |||||
} | |||||
#[delete("/users_chirho/<id_chirho>")] | |||||
pub async fn delete_user_chirho(mut db_chirho: Connection<DbChirho>, id_chirho: i64) -> Option<()> { | |||||
let result_chirho = sqlx::query("DELETE FROM users_chirho WHERE id_chirho = ?") | |||||
.bind(id_chirho) | |||||
.execute(&mut **db_chirho) | |||||
.await | |||||
.expect("Failed to delete user_chirho"); | |||||
if result_chirho.rows_affected() > 0 { | |||||
Some(()) | |||||
} else { | |||||
None | |||||
} | |||||
} | |||||
@ -0,0 +1,123 @@ | |||||
/* | |||||
* For God so loved the world, that He gave His only begotten Son, that all who believe in Him should not perish but have everlasting life | |||||
*/ | |||||
use sqlx::FromRow; | |||||
use chrono::NaiveDateTime; | |||||
use rocket::serde::{Deserialize, Serialize}; | |||||
use rocket::{serde::json::Json}; | |||||
use rocket_db_pools::{sqlx, Connection}; | |||||
use sqlx::sqlite::{SqliteRow}; | |||||
use sqlx::Row; | |||||
use crate::ApiKeyChirho; | |||||
use crate::models_chirho::DbChirho; | |||||
#[derive(FromRow, Debug, Clone, PartialEq, Serialize, Deserialize)] | |||||
pub struct UserSshAuthorizedKeyChirho { | |||||
pub id_chirho: Option<i64>, | |||||
pub user_id_chirho: i64, | |||||
pub ssh_key_chirho: String, | |||||
pub created_at: Option<NaiveDateTime> | |||||
} | |||||
#[get("/ssh_keys_chirho")] | |||||
pub async fn list_ssh_keys_chirho(_api_key: ApiKeyChirho, mut db_chirho: Connection<DbChirho>) -> Json<Vec<UserSshAuthorizedKeyChirho>> { | |||||
let ssh_keys_chirho = sqlx::query( | |||||
"SELECT * FROM user_ssh_authorized_keys_chirho" | |||||
) | |||||
.map(|row: SqliteRow| UserSshAuthorizedKeyChirho { | |||||
id_chirho: row.get("id_chirho"), | |||||
user_id_chirho: row.get("user_id_chirho"), | |||||
ssh_key_chirho: row.get("ssh_key_chirho"), | |||||
created_at: row.get("created_at"), | |||||
}) | |||||
.fetch_all(&mut **db_chirho) | |||||
.await | |||||
.expect("Failed to fetch ssh_keys_chirho"); | |||||
Json(ssh_keys_chirho) | |||||
} | |||||
#[post("/ssh_keys_chirho", data = "<ssh_key_chirho>")] | |||||
pub async fn create_ssh_key_chirho(mut db_chirho: Connection<DbChirho>, ssh_key_chirho: Json<UserSshAuthorizedKeyChirho>) -> Json<UserSshAuthorizedKeyChirho> { | |||||
let new_ssh_key_chirho = sqlx::query( | |||||
r#" | |||||
INSERT INTO user_ssh_authorized_keys_chirho (user_id_chirho, ssh_key_chirho) | |||||
VALUES (?, ?) | |||||
RETURNING * | |||||
"# | |||||
) | |||||
.bind(ssh_key_chirho.user_id_chirho) | |||||
.bind(&ssh_key_chirho.ssh_key_chirho) | |||||
.map(|row: SqliteRow| UserSshAuthorizedKeyChirho { | |||||
id_chirho: row.get("id_chirho"), | |||||
user_id_chirho: row.get("user_id_chirho"), | |||||
ssh_key_chirho: row.get("ssh_key_chirho"), | |||||
created_at: row.get("created_at"), | |||||
}) | |||||
.fetch_one(&mut **db_chirho) | |||||
.await | |||||
.expect("Failed to create ssh_key_chirho"); | |||||
Json(new_ssh_key_chirho) | |||||
} | |||||
#[get("/ssh_keys_chirho/<id_chirho>")] | |||||
pub async fn read_ssh_key_chirho(mut db_chirho: Connection<DbChirho>, id_chirho: i64) -> Option<Json<UserSshAuthorizedKeyChirho>> { | |||||
let ssh_key_chirho = sqlx::query( | |||||
"SELECT * FROM user_ssh_authorized_keys_chirho WHERE id_chirho = ?" | |||||
) | |||||
.bind(id_chirho) | |||||
.map(|row: SqliteRow| UserSshAuthorizedKeyChirho { | |||||
id_chirho: row.get("id_chirho"), | |||||
user_id_chirho: row.get("user_id_chirho"), | |||||
ssh_key_chirho: row.get("ssh_key_chirho"), | |||||
created_at: row.get("created_at"), | |||||
}) | |||||
.fetch_optional(&mut **db_chirho) | |||||
.await | |||||
.expect("Failed to fetch ssh_key_chirho"); | |||||
ssh_key_chirho.map(Json) | |||||
} | |||||
#[put("/ssh_keys_chirho/<id_chirho>", data = "<ssh_key_chirho>")] | |||||
pub async fn update_ssh_key_chirho(mut db_chirho: Connection<DbChirho>, id_chirho: i64, ssh_key_chirho: Json<UserSshAuthorizedKeyChirho>) -> Option<Json<UserSshAuthorizedKeyChirho>> { | |||||
let updated_ssh_key_chirho = sqlx::query( | |||||
r#" | |||||
UPDATE user_ssh_authorized_keys_chirho | |||||
SET user_id_chirho = ?, ssh_key_chirho = ? | |||||
WHERE id_chirho = ? | |||||
RETURNING * | |||||
"# | |||||
) | |||||
.bind(ssh_key_chirho.user_id_chirho) | |||||
.bind(&ssh_key_chirho.ssh_key_chirho) | |||||
.bind(id_chirho) | |||||
.map(|row: SqliteRow| UserSshAuthorizedKeyChirho { | |||||
id_chirho: row.get("id_chirho"), | |||||
user_id_chirho: row.get("user_id_chirho"), | |||||
ssh_key_chirho: row.get("ssh_key_chirho"), | |||||
created_at: row.get("created_at"), | |||||
}) | |||||
.fetch_optional(&mut **db_chirho) | |||||
.await | |||||
.expect("Failed to update ssh_key_chirho"); | |||||
updated_ssh_key_chirho.map(Json) | |||||
} | |||||
#[delete("/ssh_keys_chirho/<id_chirho>")] | |||||
pub async fn delete_ssh_key_chirho(mut db_chirho: Connection<DbChirho>, id_chirho: i64) -> Option<()> { | |||||
let result_chirho = sqlx::query("DELETE FROM user_ssh_authorized_keys_chirho WHERE id_chirho = ?") | |||||
.bind(id_chirho) | |||||
.execute(&mut **db_chirho) | |||||
.await | |||||
.expect("Failed to delete ssh_key_chirho"); | |||||
if result_chirho.rows_affected() > 0 { | |||||
Some(()) | |||||
} else { | |||||
None | |||||
} | |||||
} |