2020-04-09 19:04:31 +00:00
|
|
|
pub mod activities;
|
2019-12-19 21:59:13 +00:00
|
|
|
pub mod community;
|
2020-04-10 11:37:35 +00:00
|
|
|
pub mod fetcher;
|
2020-04-09 19:04:31 +00:00
|
|
|
pub mod inbox;
|
2019-12-19 21:59:13 +00:00
|
|
|
pub mod post;
|
|
|
|
pub mod user;
|
|
|
|
use crate::Settings;
|
2020-04-03 04:12:05 +00:00
|
|
|
use openssl::{pkey::PKey, rsa::Rsa};
|
2019-12-19 21:59:13 +00:00
|
|
|
|
2020-04-07 21:02:32 +00:00
|
|
|
use activitystreams::actor::{properties::ApActorProperties, Group, Person};
|
2020-04-03 05:02:43 +00:00
|
|
|
use activitystreams::ext::Ext;
|
2020-03-16 17:30:25 +00:00
|
|
|
use actix_web::body::Body;
|
|
|
|
use actix_web::HttpResponse;
|
2020-03-12 00:01:25 +00:00
|
|
|
use url::Url;
|
2019-12-19 21:59:13 +00:00
|
|
|
|
2020-04-03 05:02:43 +00:00
|
|
|
type GroupExt = Ext<Group, ApActorProperties>;
|
2020-04-07 21:02:32 +00:00
|
|
|
type PersonExt = Ext<Person, ApActorProperties>;
|
2020-04-03 05:02:43 +00:00
|
|
|
|
2020-04-07 15:29:23 +00:00
|
|
|
static APUB_JSON_CONTENT_TYPE: &str = "application/activity+json";
|
|
|
|
|
2020-04-08 16:22:44 +00:00
|
|
|
pub enum EndpointType {
|
|
|
|
Community,
|
|
|
|
User,
|
|
|
|
Post,
|
|
|
|
Comment,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Instance {
|
|
|
|
domain: String,
|
|
|
|
}
|
|
|
|
|
2020-03-19 01:16:17 +00:00
|
|
|
fn create_apub_response<T>(json: &T) -> HttpResponse<Body>
|
|
|
|
where
|
|
|
|
T: serde::ser::Serialize,
|
|
|
|
{
|
2020-03-16 17:30:25 +00:00
|
|
|
HttpResponse::Ok()
|
2020-04-07 15:29:23 +00:00
|
|
|
.content_type(APUB_JSON_CONTENT_TYPE)
|
2020-03-19 01:16:17 +00:00
|
|
|
.json(json)
|
2019-12-19 21:59:13 +00:00
|
|
|
}
|
|
|
|
|
2020-04-07 11:21:30 +00:00
|
|
|
// TODO: we will probably need to change apub endpoint urls so that html and activity+json content
|
|
|
|
// types are handled at the same endpoint, so that you can copy the url into mastodon search
|
|
|
|
// and have it fetch the object.
|
2020-04-03 04:12:05 +00:00
|
|
|
pub fn make_apub_endpoint(endpoint_type: EndpointType, name: &str) -> Url {
|
2020-03-16 18:19:04 +00:00
|
|
|
let point = match endpoint_type {
|
2020-04-07 15:34:44 +00:00
|
|
|
EndpointType::Community => "c",
|
|
|
|
EndpointType::User => "u",
|
|
|
|
EndpointType::Post => "p",
|
|
|
|
EndpointType::Comment => todo!(),
|
2020-03-16 18:19:04 +00:00
|
|
|
};
|
|
|
|
|
2020-03-12 00:01:25 +00:00
|
|
|
Url::parse(&format!(
|
2020-02-29 17:38:47 +00:00
|
|
|
"{}://{}/federation/{}/{}",
|
|
|
|
get_apub_protocol_string(),
|
2019-12-19 21:59:13 +00:00
|
|
|
Settings::get().hostname,
|
|
|
|
point,
|
2020-03-16 18:19:04 +00:00
|
|
|
name
|
2020-03-12 00:01:25 +00:00
|
|
|
))
|
|
|
|
.unwrap()
|
2019-12-19 21:59:13 +00:00
|
|
|
}
|
2020-02-29 17:38:47 +00:00
|
|
|
|
2020-03-18 15:08:08 +00:00
|
|
|
pub fn get_apub_protocol_string() -> &'static str {
|
2020-03-18 21:09:00 +00:00
|
|
|
if Settings::get().federation.tls_enabled {
|
|
|
|
"https"
|
|
|
|
} else {
|
|
|
|
"http"
|
|
|
|
}
|
2020-02-29 17:38:47 +00:00
|
|
|
}
|
2020-04-03 04:12:05 +00:00
|
|
|
|
|
|
|
pub fn gen_keypair() -> (Vec<u8>, Vec<u8>) {
|
|
|
|
let rsa = Rsa::generate(2048).expect("sign::gen_keypair: key generation error");
|
|
|
|
let pkey = PKey::from_rsa(rsa).expect("sign::gen_keypair: parsing error");
|
|
|
|
(
|
|
|
|
pkey
|
|
|
|
.public_key_to_pem()
|
|
|
|
.expect("sign::gen_keypair: public key encoding error"),
|
|
|
|
pkey
|
|
|
|
.private_key_to_pem_pkcs8()
|
|
|
|
.expect("sign::gen_keypair: private key encoding error"),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn gen_keypair_str() -> (String, String) {
|
|
|
|
let (public_key, private_key) = gen_keypair();
|
|
|
|
(vec_bytes_to_str(public_key), vec_bytes_to_str(private_key))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn vec_bytes_to_str(bytes: Vec<u8>) -> String {
|
|
|
|
String::from_utf8_lossy(&bytes).into_owned()
|
|
|
|
}
|
2020-04-03 16:32:09 +00:00
|
|
|
|
|
|
|
/// If community is on local instance, don't include the @instance part. This is only for displaying
|
|
|
|
/// to the user and should never be used otherwise.
|
|
|
|
pub fn format_community_name(name: &str, instance: &str) -> String {
|
|
|
|
if instance == Settings::get().hostname {
|
|
|
|
format!("!{}", name)
|
|
|
|
} else {
|
|
|
|
format!("!{}@{}", name, instance)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-08 16:22:44 +00:00
|
|
|
pub fn get_following_instances() -> Vec<Instance> {
|
2020-04-03 16:32:09 +00:00
|
|
|
Settings::get()
|
|
|
|
.federation
|
|
|
|
.followed_instances
|
|
|
|
.split(',')
|
2020-04-08 16:22:44 +00:00
|
|
|
.map(|i| Instance {
|
|
|
|
domain: i.to_string(),
|
|
|
|
})
|
2020-04-03 16:32:09 +00:00
|
|
|
.collect()
|
|
|
|
}
|