Add nodeinfo support

This commit is contained in:
asonix 2020-03-19 14:05:16 -05:00
parent 19e23fbfa5
commit 790d0965fb
4 changed files with 117 additions and 3 deletions

View file

@ -14,6 +14,7 @@ mod db_actor;
mod error; mod error;
mod inbox; mod inbox;
mod label; mod label;
mod nodeinfo;
mod notify; mod notify;
mod requests; mod requests;
mod state; mod state;
@ -126,7 +127,12 @@ async fn main() -> Result<(), anyhow::Error> {
.route(web::post().to(inbox::inbox)), .route(web::post().to(inbox::inbox)),
) )
.service(web::resource("/actor").route(web::get().to(actor_route))) .service(web::resource("/actor").route(web::get().to(actor_route)))
.service(actix_webfinger::resource::<_, RelayResolver>()) .service(web::resource("/nodeinfo/2.0").route(web::get().to(nodeinfo::route)))
.service(
web::scope("/.well-known")
.service(actix_webfinger::scoped::<_, RelayResolver>())
.service(web::resource("/nodeinfo").route(web::get().to(nodeinfo::well_known))),
)
}) })
.bind("0.0.0.0:8080")? .bind("0.0.0.0:8080")?
.run() .run()

81
src/nodeinfo.rs Normal file
View file

@ -0,0 +1,81 @@
use crate::state::{State, UrlKind};
use actix_web::{web, Responder};
use actix_webfinger::Link;
use std::collections::HashMap;
pub async fn well_known(state: web::Data<State>) -> impl Responder {
web::Json(Link {
rel: "http://nodeinfo.diaspora.software/ns/schema/2.0".to_owned(),
href: Some(state.generate_url(UrlKind::NodeInfo)),
template: None,
kind: None,
})
.with_header("Content-Type", "application/jrd+json")
}
pub async fn route(state: web::Data<State>) -> web::Json<NodeInfo> {
web::Json(NodeInfo {
version: NodeInfoVersion,
software: Software {
name: state.software_name(),
version: state.software_version(),
},
protocols: vec![Protocol::ActivityPub],
services: vec![],
open_registrations: false,
usage: Usage {
local_posts: 0,
local_comments: 0,
},
metadata: Metadata::default(),
})
}
#[derive(Clone, Debug, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct NodeInfo {
version: NodeInfoVersion,
software: Software,
protocols: Vec<Protocol>,
services: Vec<Service>,
open_registrations: bool,
usage: Usage,
metadata: Metadata,
}
#[derive(Clone, Debug, Default)]
pub struct NodeInfoVersion;
#[derive(Clone, Debug, Default, serde::Serialize)]
pub struct Software {
name: String,
version: String,
}
#[derive(Clone, Debug, serde::Serialize)]
pub enum Protocol {
ActivityPub,
}
#[derive(Clone, Debug, serde::Serialize)]
pub enum Service {}
#[derive(Clone, Debug, Default, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Usage {
local_posts: u64,
local_comments: u64,
}
#[derive(Clone, Debug, Default, serde::Serialize)]
#[serde(transparent)]
pub struct Metadata(pub HashMap<String, serde_json::Value>);
impl serde::ser::Serialize for NodeInfoVersion {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
serializer.serialize_str("2.0")
}
}

View file

@ -15,16 +15,23 @@ pub struct Requests {
private_key: RSAPrivateKey, private_key: RSAPrivateKey,
actor_cache: ActorCache, actor_cache: ActorCache,
config: Config, config: Config,
user_agent: String,
} }
impl Requests { impl Requests {
pub fn new(key_id: String, private_key: RSAPrivateKey, actor_cache: ActorCache) -> Self { pub fn new(
key_id: String,
private_key: RSAPrivateKey,
actor_cache: ActorCache,
user_agent: String,
) -> Self {
Requests { Requests {
client: Client::default(), client: Client::default(),
key_id, key_id,
private_key, private_key,
actor_cache, actor_cache,
config: Config::default().dont_use_created_field(), config: Config::default().dont_use_created_field(),
user_agent,
} }
} }
@ -48,6 +55,7 @@ impl Requests {
.client .client
.get(url) .get(url)
.header("Accept", "application/activity+json") .header("Accept", "application/activity+json")
.header("User-Agent", self.user_agent.as_str())
.signature(&self.config, &self.key_id, |signing_string| { .signature(&self.config, &self.key_id, |signing_string| {
self.sign(signing_string) self.sign(signing_string)
})? })?
@ -105,7 +113,7 @@ impl Requests {
.post(inbox.as_str()) .post(inbox.as_str())
.header("Accept", "application/activity+json") .header("Accept", "application/activity+json")
.header("Content-Type", "application/activity+json") .header("Content-Type", "application/activity+json")
.header("User-Agent", "Aode Relay v0.1.0") .header("User-Agent", self.user_agent.as_str())
.signature_with_digest( .signature_with_digest(
&self.config, &self.config,
&self.key_id, &self.key_id,

View file

@ -40,6 +40,7 @@ pub enum UrlKind {
Following, Following,
Inbox, Inbox,
MainKey, MainKey,
NodeInfo,
Outbox, Outbox,
} }
@ -92,6 +93,7 @@ impl Settings {
UrlKind::Following => format!("{}://{}/following", scheme, self.hostname), UrlKind::Following => format!("{}://{}/following", scheme, self.hostname),
UrlKind::Inbox => format!("{}://{}/inbox", scheme, self.hostname), UrlKind::Inbox => format!("{}://{}/inbox", scheme, self.hostname),
UrlKind::MainKey => format!("{}://{}/actor#main-key", scheme, self.hostname), UrlKind::MainKey => format!("{}://{}/actor#main-key", scheme, self.hostname),
UrlKind::NodeInfo => format!("{}://{}/nodeinfo/2.0", scheme, self.hostname),
UrlKind::Outbox => format!("{}://{}/outbox", scheme, self.hostname), UrlKind::Outbox => format!("{}://{}/outbox", scheme, self.hostname),
} }
} }
@ -99,14 +101,31 @@ impl Settings {
fn generate_resource(&self) -> String { fn generate_resource(&self) -> String {
format!("relay@{}", self.hostname) format!("relay@{}", self.hostname)
} }
fn software_name(&self) -> String {
"AodeRelay".to_owned()
}
fn software_version(&self) -> String {
"v0.1.0-master".to_owned()
}
} }
impl State { impl State {
pub fn software_name(&self) -> String {
self.settings.software_name()
}
pub fn software_version(&self) -> String {
self.settings.software_version()
}
pub fn requests(&self) -> Requests { pub fn requests(&self) -> Requests {
Requests::new( Requests::new(
self.generate_url(UrlKind::MainKey), self.generate_url(UrlKind::MainKey),
self.settings.private_key.clone(), self.settings.private_key.clone(),
self.actor_cache.clone(), self.actor_cache.clone(),
format!("{} {}", self.software_name(), self.software_version()),
) )
} }