| @ -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 | |||
| } | |||
| } | |||