2022-02-23 23:07:51 +00:00
|
|
|
use actix_web::HttpRequest;
|
2022-04-13 22:30:41 +00:00
|
|
|
use serde::de::DeserializeOwned;
|
2021-04-09 00:22:17 +00:00
|
|
|
use serde_json::Value;
|
2021-10-09 22:58:21 +00:00
|
|
|
use tokio_postgres::GenericClient;
|
2021-04-09 00:22:17 +00:00
|
|
|
|
2021-12-28 18:34:13 +00:00
|
|
|
use crate::config::Config;
|
2022-05-30 23:08:49 +00:00
|
|
|
use crate::errors::{ConversionError, HttpError, ValidationError};
|
2022-02-23 23:07:51 +00:00
|
|
|
use crate::http_signatures::verify::verify_http_signature;
|
2022-05-30 22:50:57 +00:00
|
|
|
use super::activity::{Activity, Object};
|
|
|
|
use super::fetcher::helpers::import_post;
|
2022-05-30 22:23:06 +00:00
|
|
|
use super::handlers::{
|
2022-05-30 23:08:49 +00:00
|
|
|
accept_follow::handle_accept_follow,
|
2022-07-16 01:35:10 +00:00
|
|
|
add::handle_add,
|
2022-05-30 22:23:06 +00:00
|
|
|
announce::handle_announce,
|
|
|
|
delete::handle_delete,
|
2022-05-30 22:50:57 +00:00
|
|
|
follow::handle_follow,
|
2022-05-30 22:29:09 +00:00
|
|
|
like::handle_like,
|
2022-05-30 23:08:49 +00:00
|
|
|
reject_follow::handle_reject_follow,
|
2022-07-16 01:35:10 +00:00
|
|
|
remove::handle_remove,
|
2022-05-30 23:08:49 +00:00
|
|
|
undo::handle_undo,
|
|
|
|
undo_follow::handle_undo_follow,
|
2022-05-30 22:23:06 +00:00
|
|
|
update_note::handle_update_note,
|
|
|
|
update_person::handle_update_person,
|
|
|
|
};
|
2021-04-09 00:22:17 +00:00
|
|
|
use super::vocabulary::*;
|
|
|
|
|
2022-04-13 22:30:41 +00:00
|
|
|
/// Transforms arbitrary property value into array of strings
|
2022-05-02 00:24:44 +00:00
|
|
|
pub fn parse_array(value: &Value) -> Result<Vec<String>, ConversionError> {
|
2021-11-18 23:24:13 +00:00
|
|
|
let result = match value {
|
|
|
|
Value::String(string) => vec![string.to_string()],
|
|
|
|
Value::Array(array) => {
|
2021-12-24 15:13:25 +00:00
|
|
|
let mut results = vec![];
|
|
|
|
for value in array {
|
|
|
|
match value {
|
|
|
|
Value::String(string) => results.push(string.to_string()),
|
|
|
|
Value::Object(object) => {
|
|
|
|
if let Some(string) = object["id"].as_str() {
|
|
|
|
results.push(string.to_string());
|
|
|
|
} else {
|
|
|
|
// id property is missing
|
|
|
|
return Err(ConversionError);
|
|
|
|
};
|
|
|
|
},
|
|
|
|
// Unexpected array item type
|
|
|
|
_ => return Err(ConversionError),
|
|
|
|
};
|
|
|
|
};
|
|
|
|
results
|
2021-11-18 23:24:13 +00:00
|
|
|
},
|
2021-12-24 15:13:25 +00:00
|
|
|
// Unexpected value type
|
|
|
|
_ => return Err(ConversionError),
|
2021-11-18 23:24:13 +00:00
|
|
|
};
|
|
|
|
Ok(result)
|
|
|
|
}
|
|
|
|
|
2022-04-13 22:30:41 +00:00
|
|
|
/// Transforms arbitrary property value into array of structs
|
2022-05-02 00:24:44 +00:00
|
|
|
pub fn parse_property_value<T: DeserializeOwned>(value: &Value) -> Result<Vec<T>, ConversionError> {
|
2022-04-13 22:30:41 +00:00
|
|
|
let objects = match value {
|
|
|
|
Value::Array(array) => array.to_vec(),
|
|
|
|
Value::Object(_) => vec![value.clone()],
|
|
|
|
// Unexpected value type
|
|
|
|
_ => return Err(ConversionError),
|
|
|
|
};
|
|
|
|
let mut items = vec![];
|
|
|
|
for object in objects {
|
|
|
|
let item: T = serde_json::from_value(object)
|
|
|
|
.map_err(|_| ConversionError)?;
|
|
|
|
items.push(item);
|
|
|
|
};
|
|
|
|
Ok(items)
|
|
|
|
}
|
|
|
|
|
2021-11-29 20:45:36 +00:00
|
|
|
/// Parses object json value and returns its ID as string
|
2022-07-15 17:31:02 +00:00
|
|
|
pub fn find_object_id(object: &Value) -> Result<String, ValidationError> {
|
2021-11-29 20:45:36 +00:00
|
|
|
let object_id = match object.as_str() {
|
|
|
|
Some(object_id) => object_id.to_owned(),
|
|
|
|
None => {
|
2022-05-30 19:51:32 +00:00
|
|
|
let object_id = object["id"].as_str()
|
|
|
|
.ok_or(ValidationError("missing object ID"))?
|
|
|
|
.to_string();
|
|
|
|
object_id
|
2021-11-29 20:45:36 +00:00
|
|
|
},
|
|
|
|
};
|
|
|
|
Ok(object_id)
|
|
|
|
}
|
|
|
|
|
2022-01-03 19:33:29 +00:00
|
|
|
fn require_actor_signature(actor_id: &str, signer_id: &str)
|
|
|
|
-> Result<(), HttpError>
|
|
|
|
{
|
|
|
|
if actor_id != signer_id {
|
2022-05-02 20:56:13 +00:00
|
|
|
// Forwarded activity
|
2022-01-04 14:42:03 +00:00
|
|
|
log::warn!(
|
|
|
|
"request signer {} does not match actor {}",
|
|
|
|
signer_id,
|
|
|
|
actor_id,
|
|
|
|
);
|
2022-01-03 19:33:29 +00:00
|
|
|
return Err(HttpError::AuthError("actor and request signer do not match"));
|
|
|
|
};
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-04-09 00:22:17 +00:00
|
|
|
pub async fn receive_activity(
|
|
|
|
config: &Config,
|
2022-02-23 23:07:51 +00:00
|
|
|
db_client: &mut impl GenericClient,
|
|
|
|
request: &HttpRequest,
|
2021-12-21 00:14:12 +00:00
|
|
|
activity_raw: &Value,
|
2021-04-09 00:22:17 +00:00
|
|
|
) -> Result<(), HttpError> {
|
2021-12-21 00:14:12 +00:00
|
|
|
let activity: Activity = serde_json::from_value(activity_raw.clone())
|
2021-04-09 00:22:17 +00:00
|
|
|
.map_err(|_| ValidationError("invalid activity"))?;
|
2022-05-02 11:29:03 +00:00
|
|
|
let activity_type = activity.activity_type.clone();
|
|
|
|
let activity_actor = activity.actor.clone();
|
2021-12-17 23:47:46 +00:00
|
|
|
let maybe_object_type = activity.object.get("type")
|
2021-04-09 00:22:17 +00:00
|
|
|
.and_then(|val| val.as_str())
|
2021-12-17 23:47:46 +00:00
|
|
|
.unwrap_or("Unknown");
|
2022-05-30 17:35:43 +00:00
|
|
|
|
2022-05-30 19:51:32 +00:00
|
|
|
let is_self_delete = if activity_type == DELETE {
|
2022-07-15 17:31:02 +00:00
|
|
|
let object_id = find_object_id(&activity.object)?;
|
2022-05-30 19:51:32 +00:00
|
|
|
activity.actor == object_id
|
|
|
|
} else { false };
|
|
|
|
// Don't fetch signer if this is Delete(Person) activity
|
|
|
|
let signer = match verify_http_signature(config, db_client, request, is_self_delete).await {
|
2022-05-30 17:35:43 +00:00
|
|
|
Ok(signer) => signer,
|
|
|
|
Err(error) => {
|
2022-05-30 19:51:32 +00:00
|
|
|
if is_self_delete {
|
2022-05-30 17:35:43 +00:00
|
|
|
// Ignore Delete(Person) activities without HTTP signatures
|
|
|
|
return Ok(());
|
|
|
|
};
|
|
|
|
log::warn!("invalid signature: {}", error);
|
|
|
|
return Err(HttpError::AuthError("invalid signature"));
|
|
|
|
},
|
|
|
|
};
|
|
|
|
let signer_id = signer.actor_id(&config.instance_url());
|
|
|
|
log::debug!("activity signed by {}", signer_id);
|
|
|
|
if config.blocked_instances.iter().any(|instance| signer.acct.contains(instance)) {
|
2022-06-14 19:46:46 +00:00
|
|
|
log::warn!("ignoring activity from blocked instance: {}", activity_raw);
|
|
|
|
return Ok(());
|
2022-05-30 17:35:43 +00:00
|
|
|
};
|
|
|
|
|
2022-05-30 21:48:41 +00:00
|
|
|
let maybe_object_type = match (activity_type.as_str(), maybe_object_type) {
|
2021-04-09 00:22:17 +00:00
|
|
|
(ACCEPT, FOLLOW) => {
|
2022-02-23 23:07:51 +00:00
|
|
|
require_actor_signature(&activity.actor, &signer_id)?;
|
2022-05-30 23:08:49 +00:00
|
|
|
handle_accept_follow(config, db_client, activity).await?
|
2021-09-20 21:06:48 +00:00
|
|
|
},
|
|
|
|
(REJECT, FOLLOW) => {
|
2022-02-23 23:07:51 +00:00
|
|
|
require_actor_signature(&activity.actor, &signer_id)?;
|
2022-05-30 23:08:49 +00:00
|
|
|
handle_reject_follow(config, db_client, activity).await?
|
2021-04-09 00:22:17 +00:00
|
|
|
},
|
2022-04-29 13:15:16 +00:00
|
|
|
(CREATE, NOTE | QUESTION | PAGE) => {
|
2021-04-09 00:22:17 +00:00
|
|
|
let object: Object = serde_json::from_value(activity.object)
|
|
|
|
.map_err(|_| ValidationError("invalid object"))?;
|
2022-01-03 19:33:29 +00:00
|
|
|
let object_id = object.id.clone();
|
|
|
|
let object_received = if activity.actor == signer_id {
|
|
|
|
Some(object)
|
|
|
|
} else {
|
2022-01-03 23:38:11 +00:00
|
|
|
// Fetch forwarded note, don't trust the sender
|
2022-01-03 19:33:29 +00:00
|
|
|
None
|
|
|
|
};
|
2022-04-13 19:16:34 +00:00
|
|
|
import_post(config, db_client, object_id, object_received).await?;
|
2022-05-30 21:48:41 +00:00
|
|
|
Some(NOTE)
|
2021-04-09 00:22:17 +00:00
|
|
|
},
|
2021-11-25 21:28:06 +00:00
|
|
|
(ANNOUNCE, _) => {
|
2022-02-23 23:07:51 +00:00
|
|
|
require_actor_signature(&activity.actor, &signer_id)?;
|
2022-05-30 22:23:06 +00:00
|
|
|
handle_announce(config, db_client, activity).await?
|
2021-11-25 21:28:06 +00:00
|
|
|
},
|
2021-11-19 00:05:39 +00:00
|
|
|
(DELETE, _) => {
|
2022-05-02 20:56:13 +00:00
|
|
|
if signer_id != activity.actor {
|
|
|
|
// Ignore forwarded Delete() activities
|
|
|
|
return Ok(());
|
|
|
|
};
|
2022-05-30 20:45:53 +00:00
|
|
|
handle_delete(config, db_client, activity).await?
|
2021-11-12 14:51:03 +00:00
|
|
|
},
|
2022-04-29 13:15:16 +00:00
|
|
|
(EMOJI_REACT | LIKE, _) => {
|
2022-02-23 23:07:51 +00:00
|
|
|
require_actor_signature(&activity.actor, &signer_id)?;
|
2022-05-30 22:29:09 +00:00
|
|
|
handle_like(config, db_client, activity).await?
|
2021-10-29 19:21:26 +00:00
|
|
|
},
|
2021-04-09 00:22:17 +00:00
|
|
|
(FOLLOW, _) => {
|
2022-02-23 23:07:51 +00:00
|
|
|
require_actor_signature(&activity.actor, &signer_id)?;
|
2022-05-30 22:50:57 +00:00
|
|
|
handle_follow(config, db_client, activity).await?
|
2021-04-09 00:22:17 +00:00
|
|
|
},
|
|
|
|
(UNDO, FOLLOW) => {
|
2022-02-23 23:07:51 +00:00
|
|
|
require_actor_signature(&activity.actor, &signer_id)?;
|
2022-05-30 23:08:49 +00:00
|
|
|
handle_undo_follow(config, db_client, activity).await?
|
2021-04-09 00:22:17 +00:00
|
|
|
},
|
2021-12-15 01:00:42 +00:00
|
|
|
(UNDO, _) => {
|
2022-02-23 23:07:51 +00:00
|
|
|
require_actor_signature(&activity.actor, &signer_id)?;
|
2022-05-30 23:08:49 +00:00
|
|
|
handle_undo(db_client, activity).await?
|
2021-12-15 01:00:42 +00:00
|
|
|
},
|
2022-05-11 12:50:36 +00:00
|
|
|
(UPDATE, NOTE) => {
|
|
|
|
require_actor_signature(&activity.actor, &signer_id)?;
|
|
|
|
let object: Object = serde_json::from_value(activity.object)
|
|
|
|
.map_err(|_| ValidationError("invalid object"))?;
|
2022-05-30 21:48:41 +00:00
|
|
|
handle_update_note(db_client, &config.instance_url(), object).await?
|
2022-05-11 12:50:36 +00:00
|
|
|
},
|
2021-04-09 00:22:17 +00:00
|
|
|
(UPDATE, PERSON) => {
|
2022-02-23 23:07:51 +00:00
|
|
|
require_actor_signature(&activity.actor, &signer_id)?;
|
2022-05-30 23:08:49 +00:00
|
|
|
handle_update_person(db_client, &config.media_dir(), activity).await?
|
2021-04-09 00:22:17 +00:00
|
|
|
},
|
2022-07-16 01:35:10 +00:00
|
|
|
(ADD, _) => {
|
|
|
|
require_actor_signature(&activity.actor, &signer_id)?;
|
|
|
|
handle_add(config, db_client, activity).await?
|
|
|
|
},
|
|
|
|
(REMOVE, _) => {
|
|
|
|
require_actor_signature(&activity.actor, &signer_id)?;
|
|
|
|
handle_remove(config, db_client, activity).await?
|
|
|
|
},
|
2021-04-09 00:22:17 +00:00
|
|
|
_ => {
|
2022-05-27 22:46:07 +00:00
|
|
|
log::warn!("activity type is not supported: {}", activity_raw);
|
|
|
|
return Ok(());
|
2021-04-09 00:22:17 +00:00
|
|
|
},
|
|
|
|
};
|
2022-05-30 21:48:41 +00:00
|
|
|
if let Some(object_type) = maybe_object_type {
|
|
|
|
log::info!(
|
|
|
|
"processed {}({}) from {}",
|
|
|
|
activity_type,
|
|
|
|
object_type,
|
|
|
|
activity_actor,
|
|
|
|
);
|
|
|
|
};
|
2021-04-09 00:22:17 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2021-11-18 23:24:13 +00:00
|
|
|
use serde_json::json;
|
2021-04-09 00:22:17 +00:00
|
|
|
use super::*;
|
|
|
|
|
2021-11-18 23:24:13 +00:00
|
|
|
#[test]
|
|
|
|
fn test_parse_array_with_string() {
|
|
|
|
let value = json!("test");
|
|
|
|
assert_eq!(
|
|
|
|
parse_array(&value).unwrap(),
|
|
|
|
vec!["test".to_string()],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_parse_array_with_array() {
|
|
|
|
let value = json!(["test1", "test2"]);
|
|
|
|
assert_eq!(
|
|
|
|
parse_array(&value).unwrap(),
|
|
|
|
vec!["test1".to_string(), "test2".to_string()],
|
|
|
|
);
|
|
|
|
}
|
2021-11-29 20:45:36 +00:00
|
|
|
|
2021-12-24 15:13:25 +00:00
|
|
|
#[test]
|
|
|
|
fn test_parse_array_with_array_of_objects() {
|
|
|
|
let value = json!([{"id": "test1"}, {"id": "test2"}]);
|
|
|
|
assert_eq!(
|
|
|
|
parse_array(&value).unwrap(),
|
|
|
|
vec!["test1".to_string(), "test2".to_string()],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-11-29 20:45:36 +00:00
|
|
|
#[test]
|
2022-07-15 17:31:02 +00:00
|
|
|
fn test_find_object_id_from_string() {
|
2021-11-29 20:45:36 +00:00
|
|
|
let value = json!("test_id");
|
2022-07-15 17:31:02 +00:00
|
|
|
assert_eq!(find_object_id(&value).unwrap(), "test_id");
|
2021-11-29 20:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2022-07-15 17:31:02 +00:00
|
|
|
fn test_find_object_id_from_object() {
|
2021-11-29 20:45:36 +00:00
|
|
|
let value = json!({"id": "test_id", "type": "Note"});
|
2022-07-15 17:31:02 +00:00
|
|
|
assert_eq!(find_object_id(&value).unwrap(), "test_id");
|
2021-11-29 20:45:36 +00:00
|
|
|
}
|
2021-04-09 00:22:17 +00:00
|
|
|
}
|