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