Check view permissions when interacting with post
This commit is contained in:
parent
c578d8536f
commit
562f92512e
5 changed files with 78 additions and 4 deletions
|
@ -72,6 +72,7 @@ async fn search_profiles(
|
||||||
Ok(profiles)
|
Ok(profiles)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Finds public post by its object ID
|
||||||
async fn search_note(
|
async fn search_note(
|
||||||
config: &Config,
|
config: &Config,
|
||||||
db_client: &mut impl GenericClient,
|
db_client: &mut impl GenericClient,
|
||||||
|
|
|
@ -19,6 +19,7 @@ use crate::ipfs::store as ipfs_store;
|
||||||
use crate::ipfs::utils::{IPFS_LOGO, get_ipfs_url};
|
use crate::ipfs::utils::{IPFS_LOGO, get_ipfs_url};
|
||||||
use crate::mastodon_api::oauth::auth::get_current_user;
|
use crate::mastodon_api::oauth::auth::get_current_user;
|
||||||
use crate::models::attachments::queries::set_attachment_ipfs_cid;
|
use crate::models::attachments::queries::set_attachment_ipfs_cid;
|
||||||
|
use crate::models::posts::helpers::can_view_post;
|
||||||
use crate::models::posts::mentions::{find_mentioned_profiles, replace_mentions};
|
use crate::models::posts::mentions::{find_mentioned_profiles, replace_mentions};
|
||||||
use crate::models::profiles::queries::get_followers;
|
use crate::models::profiles::queries::get_followers;
|
||||||
use crate::models::posts::helpers::{
|
use crate::models::posts::helpers::{
|
||||||
|
@ -120,6 +121,9 @@ async fn get_status(
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
let mut post = get_post_by_id(db_client, &status_id).await?;
|
let mut post = get_post_by_id(db_client, &status_id).await?;
|
||||||
|
if !can_view_post(maybe_current_user.as_ref(), &post) {
|
||||||
|
return Err(HttpError::NotFoundError("post"));
|
||||||
|
};
|
||||||
if let Some(user) = maybe_current_user {
|
if let Some(user) = maybe_current_user {
|
||||||
get_actions_for_post(db_client, &user.id, &mut post).await?;
|
get_actions_for_post(db_client, &user.id, &mut post).await?;
|
||||||
}
|
}
|
||||||
|
@ -167,6 +171,10 @@ async fn favourite(
|
||||||
) -> Result<HttpResponse, HttpError> {
|
) -> Result<HttpResponse, HttpError> {
|
||||||
let db_client = &mut **get_database_client(&db_pool).await?;
|
let db_client = &mut **get_database_client(&db_pool).await?;
|
||||||
let current_user = get_current_user(db_client, auth.token()).await?;
|
let current_user = get_current_user(db_client, auth.token()).await?;
|
||||||
|
let post = get_post_by_id(db_client, &status_id).await?;
|
||||||
|
if !can_view_post(Some(¤t_user), &post) {
|
||||||
|
return Err(HttpError::NotFoundError("post"));
|
||||||
|
};
|
||||||
let reaction_created = match create_reaction(
|
let reaction_created = match create_reaction(
|
||||||
db_client, ¤t_user.id, &status_id,
|
db_client, ¤t_user.id, &status_id,
|
||||||
).await {
|
).await {
|
||||||
|
@ -205,6 +213,10 @@ async fn unfavourite(
|
||||||
) -> Result<HttpResponse, HttpError> {
|
) -> Result<HttpResponse, HttpError> {
|
||||||
let db_client = &mut **get_database_client(&db_pool).await?;
|
let db_client = &mut **get_database_client(&db_pool).await?;
|
||||||
let current_user = get_current_user(db_client, auth.token()).await?;
|
let current_user = get_current_user(db_client, auth.token()).await?;
|
||||||
|
let post = get_post_by_id(db_client, &status_id).await?;
|
||||||
|
if !can_view_post(Some(¤t_user), &post) {
|
||||||
|
return Err(HttpError::NotFoundError("post"));
|
||||||
|
};
|
||||||
match delete_reaction(db_client, ¤t_user.id, &status_id).await {
|
match delete_reaction(db_client, ¤t_user.id, &status_id).await {
|
||||||
Err(DatabaseError::NotFound(_)) => (), // post not favourited
|
Err(DatabaseError::NotFound(_)) => (), // post not favourited
|
||||||
other_result => other_result?,
|
other_result => other_result?,
|
||||||
|
@ -234,6 +246,10 @@ async fn make_permanent(
|
||||||
let db_client = &**get_database_client(&db_pool).await?;
|
let db_client = &**get_database_client(&db_pool).await?;
|
||||||
let current_user = get_current_user(db_client, auth.token()).await?;
|
let current_user = get_current_user(db_client, auth.token()).await?;
|
||||||
let mut post = get_post_by_id(db_client, &status_id).await?;
|
let mut post = get_post_by_id(db_client, &status_id).await?;
|
||||||
|
if post.author.id != current_user.id || !post.is_public() {
|
||||||
|
// Users can only archive their own public posts
|
||||||
|
return Err(HttpError::NotFoundError("post"));
|
||||||
|
};
|
||||||
let ipfs_api_url = config.ipfs_api_url.as_ref()
|
let ipfs_api_url = config.ipfs_api_url.as_ref()
|
||||||
.ok_or(HttpError::NotSupported)?;
|
.ok_or(HttpError::NotSupported)?;
|
||||||
|
|
||||||
|
@ -286,10 +302,10 @@ async fn get_signature(
|
||||||
let contract_config = config.ethereum_contract.as_ref()
|
let contract_config = config.ethereum_contract.as_ref()
|
||||||
.ok_or(HttpError::NotSupported)?;
|
.ok_or(HttpError::NotSupported)?;
|
||||||
let post = get_post_by_id(db_client, &status_id).await?;
|
let post = get_post_by_id(db_client, &status_id).await?;
|
||||||
if post.author.id != current_user.id {
|
if post.author.id != current_user.id || !post.is_public() {
|
||||||
// Users can only tokenize their own posts
|
// Users can only tokenize their own public posts
|
||||||
return Err(HttpError::NotFoundError("post"));
|
return Err(HttpError::NotFoundError("post"));
|
||||||
}
|
};
|
||||||
let ipfs_cid = post.ipfs_cid
|
let ipfs_cid = post.ipfs_cid
|
||||||
// Post metadata is not immutable
|
// Post metadata is not immutable
|
||||||
.ok_or(HttpError::ValidationError("post is not immutable".into()))?;
|
.ok_or(HttpError::ValidationError("post is not immutable".into()))?;
|
||||||
|
|
|
@ -3,7 +3,8 @@ use uuid::Uuid;
|
||||||
|
|
||||||
use crate::errors::DatabaseError;
|
use crate::errors::DatabaseError;
|
||||||
use crate::models::reactions::queries::get_favourited;
|
use crate::models::reactions::queries::get_favourited;
|
||||||
use super::types::{Post, PostActions};
|
use crate::models::users::types::User;
|
||||||
|
use super::types::{Post, PostActions, Visibility};
|
||||||
|
|
||||||
pub async fn get_actions_for_post(
|
pub async fn get_actions_for_post(
|
||||||
db_client: &impl GenericClient,
|
db_client: &impl GenericClient,
|
||||||
|
@ -29,3 +30,54 @@ pub async fn get_actions_for_posts(
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn can_view_post(user: Option<&User>, post: &Post) -> bool {
|
||||||
|
match post.visibility {
|
||||||
|
Visibility::Public => true,
|
||||||
|
Visibility::Direct => {
|
||||||
|
if let Some(user) = user {
|
||||||
|
// Returns true if user is mentioned
|
||||||
|
post.mentions.iter()
|
||||||
|
.find(|profile| profile.id == user.profile.id)
|
||||||
|
.is_some()
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_can_view_post_anonymous() {
|
||||||
|
let post = Post {
|
||||||
|
visibility: Visibility::Public,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
assert!(can_view_post(None, &post));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_can_view_post_direct() {
|
||||||
|
let user = User::default();
|
||||||
|
let post = Post {
|
||||||
|
visibility: Visibility::Direct,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
assert!(!can_view_post(Some(&user), &post));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_can_view_post_direct_mentioned() {
|
||||||
|
let user = User::default();
|
||||||
|
let post = Post {
|
||||||
|
visibility: Visibility::Direct,
|
||||||
|
mentions: vec![user.profile.clone()],
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
assert!(can_view_post(Some(&user), &post));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -108,6 +108,10 @@ impl Post {
|
||||||
actions: None,
|
actions: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_public(&self) -> bool {
|
||||||
|
matches!(self.visibility, Visibility::Public)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -20,6 +20,7 @@ pub struct DbUser {
|
||||||
|
|
||||||
// Represents local user
|
// Represents local user
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
#[cfg_attr(test, derive(Default))]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
pub id: Uuid,
|
pub id: Uuid,
|
||||||
pub wallet_address: String,
|
pub wallet_address: String,
|
||||||
|
|
Loading…
Reference in a new issue