Kibou is a federated social networking server.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

controller.rs 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. use actor::create_actor as create_actor;
  2. use actor::get_actor_by_uri;
  3. use activity::get_ap_object_by_id;
  4. use activity::insert_activity;
  5. use activitypub::actor::Actor;
  6. use activitypub::actor::create_internal_actor;
  7. use activitypub::activity::Activity;
  8. use activitypub::activity::Object;
  9. use activitypub::activity::create_internal_activity;
  10. use activitypub::validator;
  11. use chrono::Utc;
  12. use database;
  13. use env;
  14. use url::Url;
  15. use uuid::Uuid;
  16. use web_handler;
  17. /// Creates a new activity, inserts it into the database and returns the newly created activity
  18. ///
  19. /// # Parameters
  20. ///
  21. /// * `actor` - String | Reference to an actor by their actor_uri
  22. /// * `object` - serde_json::Value | An ActivityStreams object serialized in JSON
  23. /// * `to` - Vec<String> | A vector of strings that provides direct receipients
  24. /// * `cc` - Vec<String> | A vector of strings that provides passive receipients
  25. ///
  26. pub fn activity_create(_actor: &str, _object: serde_json::Value, _to: Vec<String>, _cc: Vec<String>) -> Activity
  27. {
  28. let database = database::establish_connection();
  29. let new_activity = Activity
  30. {
  31. context: vec![String::from("https://www.w3.org/ns/activitystreams"), String::from("https://w3id.org/security/v1")],
  32. _type: String::from("Create"),
  33. id: format!("{base_scheme}://{base_domain}/activities/{uuid}",
  34. base_scheme = env::get_value(String::from("endpoint.base_scheme")),
  35. base_domain = env::get_value(String::from("endpoint.base_domain")),
  36. uuid = Uuid::new_v4()),
  37. actor: _actor.to_string(),
  38. object: _object,
  39. published: Utc::now().to_rfc3339().to_string(),
  40. to: _to,
  41. cc: _cc
  42. };
  43. insert_activity(&database, create_internal_activity(serde_json::json!(&new_activity), new_activity.actor.clone()));
  44. new_activity
  45. }
  46. pub fn activity_follow(_actor: &str, _object: String) -> Activity
  47. {
  48. let database = database::establish_connection();
  49. let new_activity = Activity
  50. {
  51. context: vec![String::from("https://www.w3.org/ns/activitystreams"), String::from("https://w3id.org/security/v1")],
  52. _type: String::from("Follow"),
  53. id: format!("{base_scheme}://{base_domain}/activities/{uuid}",
  54. base_scheme = env::get_value(String::from("endpoint.base_scheme")),
  55. base_domain = env::get_value(String::from("endpoint.base_domain")),
  56. uuid = Uuid::new_v4()),
  57. actor: _actor.to_string(),
  58. object: serde_json::json!(_object),
  59. published: Utc::now().to_rfc3339().to_string(),
  60. to: vec![_object],
  61. cc: vec![]
  62. };
  63. insert_activity(&database, create_internal_activity(serde_json::json!(&new_activity), new_activity.actor.clone()));
  64. new_activity
  65. }
  66. pub fn activity_like(_actor: &str, _object: String, _to: Vec<String>, _cc: Vec<String>) -> Activity
  67. {
  68. let database = database::establish_connection();
  69. let new_activity = Activity
  70. {
  71. context: vec![String::from("https://www.w3.org/ns/activitystreams"), String::from("https://w3id.org/security/v1")],
  72. _type: String::from("Like"),
  73. id: format!("{base_scheme}://{base_domain}/activities/{uuid}",
  74. base_scheme = env::get_value(String::from("endpoint.base_scheme")),
  75. base_domain = env::get_value(String::from("endpoint.base_domain")),
  76. uuid = Uuid::new_v4()),
  77. actor: _actor.to_string(),
  78. object: serde_json::json!(_object),
  79. published: Utc::now().to_rfc3339().to_string(),
  80. to: _to,
  81. cc: _cc
  82. };
  83. insert_activity(&database, create_internal_activity(serde_json::json!(&new_activity), new_activity.actor.clone()));
  84. new_activity
  85. }
  86. pub fn note(actor: &str, reply_to: Option<String>, _content: String, _to: Vec<String>, _cc: Vec<String>, _tag: Vec<serde_json::Value>) -> Object
  87. {
  88. Object
  89. {
  90. _type: String::from("Note"),
  91. id: format!("{base_scheme}://{base_domain}/objects/{uuid}",
  92. base_scheme = env::get_value(String::from("endpoint.base_scheme")),
  93. base_domain = env::get_value(String::from("endpoint.base_domain")),
  94. uuid = Uuid::new_v4()),
  95. attributedTo: actor.to_string(),
  96. inReplyTo: reply_to,
  97. summary: None, // [TODO]
  98. content: _content,
  99. published: Utc::now().to_rfc3339().to_string(),
  100. to: _to,
  101. cc: _cc,
  102. tag: _tag
  103. }
  104. }
  105. /// # Tests
  106. ///
  107. /// [TODO]
  108. pub fn fetch_object_by_id(url: String)
  109. {
  110. let mut parsed_url = String::new();
  111. let stripped_characters = "\"";
  112. for character in url.chars()
  113. {
  114. if !stripped_characters.contains(character)
  115. {
  116. parsed_url.push(character);
  117. }
  118. }
  119. match Url::parse(&parsed_url)
  120. {
  121. Ok(remote_url) =>
  122. {
  123. if !object_exists(&remote_url.to_string()) && !actor_exists(&remote_url.to_string())
  124. {
  125. println!("Trying to fetch document: {}", &url);
  126. match web_handler::fetch_remote_object(&remote_url.to_string())
  127. {
  128. Ok(object) =>
  129. {
  130. let parsed_object: serde_json::Value = serde_json::from_str(&object).unwrap();
  131. if validator::validate_object(parsed_object.clone()).is_ok()
  132. {
  133. println!("Successfully fetched object: {}", &url);
  134. handle_object(parsed_object.clone());
  135. }
  136. else if validator::validate_actor(parsed_object.clone()).is_ok()
  137. {
  138. println!("Successfully fetched actor: {}", &url);
  139. handle_actor(parsed_object.clone());
  140. }
  141. else { eprintln!("Unable to validate fetched document: {}", &url); }
  142. },
  143. Err(_) => eprintln!("Unable to fetch document: {}", &url)
  144. }
  145. }
  146. },
  147. Err(_) => ()
  148. }
  149. }
  150. /// # Tests
  151. ///
  152. /// [TODO]
  153. pub fn prepare_incoming(object: serde_json::Value)
  154. {
  155. match validator::validate_activity(object) {
  156. Ok(sanitized_activity) => handle_activity(sanitized_activity),
  157. Err(_) => {
  158. eprintln!("{}", String::from("Validation failed for activity: "));
  159. }
  160. }
  161. }
  162. /// # Tests
  163. ///
  164. /// Tests for this function are in `tests/activitypub_controller.rs`
  165. /// - actor_exists()
  166. /// - err_actor_exists()
  167. pub fn actor_exists(actor_id: &str) -> bool
  168. {
  169. let database = database::establish_connection();
  170. match get_actor_by_uri(&database, actor_id)
  171. {
  172. Ok(_) => true,
  173. Err(_) => false
  174. }
  175. }
  176. /// # Tests
  177. ///
  178. /// Tests for this function are in `tests/activitypub_controller.rs`
  179. /// - object_exists()
  180. /// - err_object_exists()
  181. pub fn object_exists(object_id: &str) -> bool
  182. {
  183. let database = database::establish_connection();
  184. match get_ap_object_by_id(&database, object_id)
  185. {
  186. Ok(_) => true,
  187. Err(_) => false
  188. }
  189. }
  190. /// # Tests
  191. ///
  192. /// [TODO]
  193. fn resolve_participants(participants: Vec<String>)
  194. {
  195. // Resolve all participants
  196. for participant in participants.iter()
  197. {
  198. if participant != "" && !actor_exists(&participant.to_string())
  199. {
  200. fetch_object_by_id(participant.to_string())
  201. }
  202. }
  203. }
  204. /// Resolve threads
  205. ///
  206. /// # Tests
  207. ///
  208. /// [TODO]
  209. fn resolve_thread(mentioned_objects: Vec<String>)
  210. {
  211. for object in mentioned_objects.iter()
  212. {
  213. if !object_exists(&object.to_string())
  214. {
  215. fetch_object_by_id(object.to_string());
  216. }
  217. }
  218. }
  219. /// # Tests
  220. ///
  221. /// [TODO]
  222. fn handle_object(object: serde_json::Value)
  223. {
  224. let serialized_object: Object = serde_json::from_value(object.clone()).unwrap();
  225. let participants = vec![serialized_object.attributedTo.clone()];
  226. let mut mentioned_objects = vec![];
  227. if !serialized_object.inReplyTo.is_none()
  228. {
  229. mentioned_objects.push(serialized_object.inReplyTo.unwrap());
  230. }
  231. // Wrapping new object in an activity, as raw objects don't get stored
  232. let activity = activity_create(&serialized_object.attributedTo, object, serialized_object.to, serialized_object.cc);
  233. if !mentioned_objects.is_empty() { resolve_thread(mentioned_objects); }
  234. if !participants.is_empty() { resolve_participants(participants); }
  235. }
  236. /// # Tests
  237. ///
  238. /// [TODO]
  239. fn handle_actor(actor: serde_json::Value)
  240. {
  241. let database = database::establish_connection();
  242. let serialized_actor: Actor = serde_json::from_value(actor).unwrap();
  243. create_actor(&database, &mut create_internal_actor(serialized_actor));
  244. }
  245. /// # Tests
  246. ///
  247. /// [TODO]
  248. fn handle_activity(activity: serde_json::Value)
  249. {
  250. let database = database::establish_connection();
  251. let actor = activity["actor"].as_str().unwrap().to_string();
  252. let mut participants = vec![];
  253. let mut mentioned_objects = vec![];
  254. match activity["type"].as_str() {
  255. Some("Create") => {
  256. participants.push(activity["actor"].as_str().unwrap().to_string());
  257. participants.push(activity["object"]["attributedTo"].as_str().unwrap().to_string());
  258. if activity["object"].get("inReplyTo").is_some()
  259. {
  260. if activity["object"]["inReplyTo"] != serde_json::Value::Null
  261. {
  262. mentioned_objects.push(activity["object"]["inReplyTo"].as_str().unwrap().to_string());
  263. }
  264. }
  265. insert_activity(&database, create_internal_activity(activity, actor));
  266. },
  267. Some("Like") => {
  268. participants.push(activity["actor"].as_str().unwrap().to_string());
  269. mentioned_objects.push(activity["object"].as_str().unwrap().to_string());
  270. insert_activity(&database, create_internal_activity(activity, actor));
  271. },
  272. Some("Announce") => {
  273. participants.push(activity["actor"].as_str().unwrap().to_string());
  274. mentioned_objects.push(activity["object"].as_str().unwrap().to_string());
  275. insert_activity(&database, create_internal_activity(activity, actor));
  276. },
  277. _ => ()
  278. }
  279. if !mentioned_objects.is_empty() { resolve_thread(mentioned_objects); }
  280. if !participants.is_empty() { resolve_participants(participants); }
  281. }