]> Untitled Git - lemmy.git/blob - server/src/apub/mod.rs
Merge branch 'dev' into federation
[lemmy.git] / server / src / apub / mod.rs
1 pub mod activities;
2 pub mod community;
3 pub mod fetcher;
4 pub mod inbox;
5 pub mod post;
6 pub mod signatures;
7 pub mod user;
8 use crate::apub::signatures::PublicKeyExtension;
9 use crate::Settings;
10 use activitystreams::actor::{properties::ApActorProperties, Group, Person};
11 use activitystreams::ext::Ext;
12 use actix_web::body::Body;
13 use actix_web::HttpResponse;
14 use openssl::{pkey::PKey, rsa::Rsa};
15 use url::Url;
16
17 type GroupExt = Ext<Ext<Group, ApActorProperties>, PublicKeyExtension>;
18 type PersonExt = Ext<Ext<Person, ApActorProperties>, PublicKeyExtension>;
19
20 static APUB_JSON_CONTENT_TYPE: &str = "application/activity+json";
21
22 pub enum EndpointType {
23   Community,
24   User,
25   Post,
26   Comment,
27 }
28
29 pub struct Instance {
30   domain: String,
31 }
32
33 fn create_apub_response<T>(json: &T) -> HttpResponse<Body>
34 where
35   T: serde::ser::Serialize,
36 {
37   HttpResponse::Ok()
38     .content_type(APUB_JSON_CONTENT_TYPE)
39     .json(json)
40 }
41
42 // TODO: we will probably need to change apub endpoint urls so that html and activity+json content
43 //       types are handled at the same endpoint, so that you can copy the url into mastodon search
44 //       and have it fetch the object.
45 pub fn make_apub_endpoint(endpoint_type: EndpointType, name: &str) -> Url {
46   let point = match endpoint_type {
47     EndpointType::Community => "c",
48     EndpointType::User => "u",
49     EndpointType::Post => "p",
50     // TODO I have to change this else my update advanced_migrations crashes the
51     // server if a comment exists.
52     EndpointType::Comment => "comment",
53   };
54
55   Url::parse(&format!(
56     "{}://{}/federation/{}/{}",
57     get_apub_protocol_string(),
58     Settings::get().hostname,
59     point,
60     name
61   ))
62   .unwrap()
63 }
64
65 pub fn get_apub_protocol_string() -> &'static str {
66   if Settings::get().federation.tls_enabled {
67     "https"
68   } else {
69     "http"
70   }
71 }
72
73 pub fn gen_keypair() -> (Vec<u8>, Vec<u8>) {
74   let rsa = Rsa::generate(2048).expect("sign::gen_keypair: key generation error");
75   let pkey = PKey::from_rsa(rsa).expect("sign::gen_keypair: parsing error");
76   (
77     pkey
78       .public_key_to_pem()
79       .expect("sign::gen_keypair: public key encoding error"),
80     pkey
81       .private_key_to_pem_pkcs8()
82       .expect("sign::gen_keypair: private key encoding error"),
83   )
84 }
85
86 pub fn gen_keypair_str() -> (String, String) {
87   let (public_key, private_key) = gen_keypair();
88   (vec_bytes_to_str(public_key), vec_bytes_to_str(private_key))
89 }
90
91 fn vec_bytes_to_str(bytes: Vec<u8>) -> String {
92   String::from_utf8_lossy(&bytes).into_owned()
93 }
94
95 /// If community is on local instance, don't include the @instance part. This is only for displaying
96 /// to the user and should never be used otherwise.
97 pub fn format_community_name(name: &str, instance: &str) -> String {
98   if instance == Settings::get().hostname {
99     format!("!{}", name)
100   } else {
101     format!("!{}@{}", name, instance)
102   }
103 }
104
105 pub fn get_following_instances() -> Vec<Instance> {
106   Settings::get()
107     .federation
108     .followed_instances
109     .split(',')
110     .map(|i| Instance {
111       domain: i.to_string(),
112     })
113     .collect()
114 }