From 5976ef880ea5a9ad2643b26f06d36e5968231015 Mon Sep 17 00:00:00 2001 From: SHAcollision Date: Mon, 26 Aug 2024 16:22:36 +0200 Subject: [PATCH] Refactor user homeserver and add validator --- src/events/mod.rs | 25 +++++++++++++++++-------- src/models/homeserver/user.rs | 14 ++++++++++++++ src/models/user/details.rs | 21 +++++++++++---------- 3 files changed, 42 insertions(+), 18 deletions(-) diff --git a/src/events/mod.rs b/src/events/mod.rs index 275d8de2..e8e1c2a4 100644 --- a/src/events/mod.rs +++ b/src/events/mod.rs @@ -1,4 +1,5 @@ use crate::models::{ + homeserver::HomeserverUser, traits::Collection, user::{UserCounts, UserDetails}, }; @@ -88,7 +89,8 @@ impl Event { if let Some(start) = self.uri.path.find(pattern) { let start_idx = start + pattern.len(); if let Some(end_idx) = self.uri.path[start_idx..].find(pub_segment) { - return Some(self.uri.path[start_idx..start_idx + end_idx].to_string()); + let user_id = self.uri.path[start_idx..start_idx + end_idx].to_string(); + return Some(user_id); } } @@ -122,16 +124,23 @@ impl Event { // Process profile.json and update the databases debug!("Processing User resource at {}", self.uri.path); - // Index new user event into the DBs + // Serialize and validate + let user = HomeserverUser::try_from(&content).await?; + + // Create UserDetails object let user_details = match self.get_user_id() { - None => return Ok(()), - Some(user_id) => UserDetails::from_homeserver(&user_id, &content).await?, + Some(user_id) => UserDetails::from_homeserver(&user_id, user).await?, + None => { + error!("Error getting user_id from event uri. Skipping event."); + return Ok(()); + } }; - if let Some(user_details) = user_details { - user_details.save().await?; - UserDetails::add_to_sorted_sets(&[Some(user_details)]).await; - } + // Index new user event into the Graph and Index + user_details.save().await?; + + // Add to other sorted sets and indexes + UserDetails::add_to_sorted_sets(&[Some(user_details)]).await; } ResourceType::Post => { // Process Post resource and update the databases diff --git a/src/models/homeserver/user.rs b/src/models/homeserver/user.rs index a188a7fd..0c437a4a 100644 --- a/src/models/homeserver/user.rs +++ b/src/models/homeserver/user.rs @@ -1,3 +1,4 @@ +use axum::body::Bytes; use serde::{Deserialize, Serialize}; use utoipa::ToSchema; @@ -17,3 +18,16 @@ pub struct UserLink { pub title: String, pub url: String, } + +impl HomeserverUser { + pub async fn try_from(blob: &Bytes) -> Result> { + let user: Self = serde_json::from_slice(blob)?; + user.validate().await?; + Ok(user) + } + + //TODO: implement full validation rules. Min/Max length of links, of bio, of username, etc. + pub async fn validate(&self) -> Result<(), Box> { + Ok(()) + } +} diff --git a/src/models/user/details.rs b/src/models/user/details.rs index cedef66c..dc9ca94f 100644 --- a/src/models/user/details.rs +++ b/src/models/user/details.rs @@ -6,6 +6,7 @@ use crate::{queries, RedisOps}; use axum::async_trait; use chrono::Utc; use neo4rs::Query; +use pkarr::PublicKey; use serde::{Deserialize, Deserializer, Serialize}; use serde_json; use utoipa::ToSchema; @@ -66,18 +67,18 @@ impl UserDetails { pub async fn from_homeserver( user_id: &str, - content: &[u8], - ) -> Result, Box> { - let user: HomeserverUser = serde_json::from_slice(content)?; - - Ok(Some(UserDetails { - name: user.name, - bio: user.bio, - status: user.status, - links: user.links, + homeserver_user: HomeserverUser, + ) -> Result> { + // Validate user_id is a valid pkarr public key + PublicKey::try_from(user_id)?; + Ok(UserDetails { + name: homeserver_user.name, + bio: homeserver_user.bio, + status: homeserver_user.status, + links: homeserver_user.links, id: user_id.to_string(), indexed_at: Utc::now().timestamp_millis(), - })) + }) } pub async fn save(&self) -> Result<(), Box> {