Can now connect to Omikron :C

Some util
This commit is contained in:
Alex Emmet 2025-09-05 23:00:24 +02:00
commit 9bd22d4e3e
16 changed files with 1508 additions and 199 deletions

View file

@ -58,9 +58,12 @@ impl Contact {
about: None,
}
}
pub fn set_last_message_at(&mut self, p0: i64) {
self.last_message_at = Option::from(p0);
}
pub fn to_json(&self) -> JsonValue {
let mut obj = self.to_json();
let mut obj = JsonValue::new_object();
if let Some(id) = &self.user_id {
obj["userID"] = JsonValue::from(id.to_string());
}

View file

@ -1 +1,5 @@
pub mod contact;
pub mod contact;
pub mod user_manager;
pub mod user_profile_full;
pub mod user_profile;
pub mod user_community_util;

View file

@ -0,0 +1,64 @@
use json::{self, JsonValue};
use std::fs;
use std::path::Path;
use uuid::Uuid;
pub struct UserCommunityUtil;
impl UserCommunityUtil {
pub fn add_community(
storage_owner: Uuid,
address: String,
title: String,
position: String,
) {
let path = format!("users/{}/communities.json", storage_owner);
let mut communities: JsonValue = Self::load_array(&path);
let mut community = JsonValue::new_object();
community["title"] = JsonValue::String(title);
community["address"] = JsonValue::String(address);
community["position"] = JsonValue::String(position);
communities.push(community);
Self::save_array(&path, communities);
}
pub fn remove_community(storage_owner: Uuid, community_address: String) {
let path = format!("users/{}/communities.json", storage_owner);
let mut communities = Self::load_array(&path);
let mut new_array = JsonValue::new_array();
for entry in communities.members() {
if entry["address"].as_str() != Some(&community_address) {
new_array.push(entry.clone()).unwrap();
}
}
Self::save_array(&path, new_array);
}
pub fn get_communities(storage_owner: Uuid) -> JsonValue {
let path = format!("users/{}/communities.json", storage_owner);
Self::load_array(&path)
}
fn load_array(path: &str) -> JsonValue {
if !Path::new(path).exists() {
return JsonValue::new_object();
}
match fs::read_to_string(path) {
Ok(content) => json::parse(&content).unwrap_or_else(|_| JsonValue::new_object()),
Err(_) => JsonValue::new_object(),
}
}
fn save_array(path: &str, arr: JsonValue) {
if let Some(parent) = Path::new(path).parent() {
let _ = fs::create_dir_all(parent);
}
let _ = fs::write(path, arr.pretty(3));
}
}

View file

@ -0,0 +1,106 @@
use std::fs;
use std::sync::Mutex;
use std::io;
use std::path::Path;
use uuid::Uuid;
use rand::Rng;
use rand::rngs::OsRng;
use base64::{engine::general_purpose, Engine as _};
use json::{JsonValue};
use once_cell::sync::Lazy;
use crate::users::user_profile::UserProfile;
use crate::users::user_profile_full::UserProfileFull;
pub struct UserManager;
static USERS: Lazy<Mutex<Vec<UserProfile>>> = Lazy::new(|| Mutex::new(Vec::new()));
static UNIQUE: Lazy<Mutex<bool>> = Lazy::new(|| Mutex::new(false));
impl UserManager {
pub fn create_user(username: &str) -> Option<UserProfileFull> {
// Stub: normally AuthConnector.getRegister() returns a UUID
let user_id = Uuid::new_v4();
// Stubbed: CryptoHelper.generateKeyPair()
let public_key = general_purpose::STANDARD.encode(b"dummy-public");
let private_key = general_purpose::STANDARD.encode(b"dummy-private");
let private_key_hash = format!("hash-{}", &private_key);
let mut bytes = [0u8; 192];
OsRng.fill(bytes.as_mut());
let reset_token = general_purpose::STANDARD.encode(&bytes);
let up = UserProfile::new(
user_id,
username.to_string(),
None,
public_key,
private_key_hash,
reset_token,
);
let up_full = UserProfileFull { user_profile: up.clone(), private_key };
USERS.lock().unwrap().push(up);
Self::save_users().ok();
Some(up_full)
}
pub fn get_user(user_id: Uuid) -> Option<UserProfile> {
USERS.lock().unwrap().iter().cloned().find(|u| u.user_id == user_id)
}
pub fn get_users() -> Vec<UserProfile> {
USERS.lock().unwrap().clone()
}
pub fn add_user(up: UserProfile) {
let mut users = USERS.lock().unwrap();
users.retain(|u| u.user_id != up.user_id);
users.push(up);
*UNIQUE.lock().unwrap() = true;
}
pub fn remove_user(user_id: Uuid) {
let mut users = USERS.lock().unwrap();
users.retain(|u| u.user_id != user_id);
*UNIQUE.lock().unwrap() = true;
}
pub fn save_users() -> io::Result<()> {
*UNIQUE.lock().unwrap() = false;
let users = USERS.lock().unwrap();
let arr: Vec<JsonValue> = users.iter().map(|u| u.to_json()).collect();
let json_str = JsonValue::Array(arr).dump();
fs::write("users.json", json_str)?;
Ok(())
}
pub async fn load_users() -> io::Result<()> {
let path = Path::new("users.json");
if !path.exists() {
return Ok(());
}
let content = fs::read_to_string(path)?;
if content.trim().is_empty() {
return Ok(());
}
let parsed = json::parse(&content).map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
if let JsonValue::Array(arr) = parsed {
let mut users = USERS.lock().unwrap();
for j in arr.iter() {
if let Some(up) = UserProfile::from_json(j).await {
users.push(up);
}
}
}
if *UNIQUE.lock().unwrap() {
Self::save_users().ok();
}
Ok(())
}
pub fn set_unique(val: bool) {
*UNIQUE.lock().unwrap() = val;
}
}

View file

@ -0,0 +1,95 @@
use std::fs;
use std::sync::Mutex;
use std::collections::HashMap;
use std::io;
use std::path::Path;
use uuid::Uuid;
use rand::Rng;
use rand::rngs::OsRng;
use base64::{engine::general_purpose, Engine as _};
use json::{JsonValue, object, stringify};
use crate::users::user_manager::UserManager;
use crate::auth::auth_connector::AuthConnector;
// --- UserProfile ---
#[derive(Clone, Debug)]
pub struct UserProfile {
pub user_id: Uuid,
pub username: String,
pub public_key: String,
pub private_key_hash: String,
pub reset_token: String,
pub display_name: Option<String>,
}
impl UserProfile {
pub fn new(
user_id: Uuid,
username: String,
display_name: Option<String>,
public_key: String,
private_key_hash: String,
reset_token: String,
) -> Self {
Self {
user_id,
username,
display_name,
public_key,
private_key_hash,
reset_token,
}
}
pub fn to_json(&self) -> JsonValue {
let mut obj = object! {
"UUID" => self.user_id.to_string(),
"username" => self.username.clone(),
"publicKey" => self.public_key.clone(),
"privateKeyHash" => self.private_key_hash.clone(),
"resetToken" => self.reset_token.clone()
};
if let Some(d) = &self.display_name {
obj["displayName"] = d.clone().into();
}
obj
}
pub async fn from_json(j: &JsonValue) -> Option<Self> {
let uuid = Uuid::parse_str(j["UUID"].as_str()?).ok()?;
let username = j["username"].as_str()?.to_string();
let public_key = j["publicKey"].as_str()?.to_string();
let private_key_hash = j["privateKeyHash"].as_str()?.to_string();
let reset_token = j["resetToken"].as_str()?.to_string();
let display_name = j["displayName"].as_str().map(|s| s.to_string());
let mut up = UserProfile::new(uuid, username, display_name, public_key, private_key_hash, reset_token);
// Migration hook (stubbed, since AuthConnector isnt implemented here)
if j.has_key("migrate")
|| j.has_key("migrating")
|| j.has_key("changing")
|| j.has_key("move")
|| j.has_key("moving") {
if AuthConnector::migrate_user(&mut up, stringify!("{}", Uuid::new_v4())).await {
println!("[INFO] Migration triggered for {}", up.username);
UserManager::set_unique(true);
}
}
Some(up)
}
pub fn randomize_reset_token(&mut self) -> String {
let mut bytes = [0u8; 192];
OsRng.fill(bytes.as_mut());
let new_token = general_purpose::STANDARD.encode(&bytes);
self.reset_token = new_token.clone();
UserManager::save_users().ok();
new_token
}
pub fn get_display_name(&self) -> String {
self.display_name.clone().unwrap_or_else(|| self.username.clone())
}
}

View file

@ -0,0 +1,8 @@
use crate::users::user_profile::UserProfile;
// --- UserProfileFull ---
#[derive(Clone, Debug)]
pub struct UserProfileFull {
pub user_profile: UserProfile,
pub private_key: String,
}