Implement NodeInfo 2.1

This commit is contained in:
silverpill 2023-03-06 19:49:45 +00:00
parent 0817177282
commit 94a5f3a3cd
4 changed files with 117 additions and 31 deletions

View file

@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Added `emojis` field to Mastodon API Account entity.
- Support audio attachments.
- Added CLI command for viewing unreachable actors.
- Implemented NodeInfo 2.1.
### Changed

View file

@ -169,8 +169,9 @@ async fn main() -> std::io::Result<()> {
.service(activitypub::emoji_view)
.service(activitypub::tag_view)
.service(atom_scope())
.service(nodeinfo::get_nodeinfo)
.service(nodeinfo::get_nodeinfo_jrd)
.service(nodeinfo::get_nodeinfo_2_0)
.service(nodeinfo::get_nodeinfo_2_1)
.service(web_client::profile_page_redirect())
.service(web_client::post_page_redirect())
.service(

View file

@ -4,16 +4,56 @@ use serde::Serialize;
use mitra_config::{Config, RegistrationType, MITRA_VERSION};
const MITRA_NAME: &str = "mitra";
const MITRA_REPOSITORY: &str = "https://codeberg.org/silverpill/mitra";
const ATOM_SERVICE: &str = "atom1.0";
const ACTIVITYPUB_PROTOCOL: &str = "activitypub";
#[derive(Serialize)]
struct Software {
struct Software20 {
name: String,
version: String,
}
impl Default for Software20 {
fn default() -> Self {
Self {
name: MITRA_NAME.to_string(),
version: MITRA_VERSION.to_string(),
}
}
}
#[derive(Serialize)]
struct Software21 {
name: String,
version: String,
repository: String,
}
impl Default for Software21 {
fn default() -> Self {
Self {
name: MITRA_NAME.to_string(),
version: MITRA_VERSION.to_string(),
repository: MITRA_REPOSITORY.to_string(),
}
}
}
#[derive(Serialize)]
struct Services {
inbound: Vec<String>,
outbound: Vec<String>,
inbound: Vec<&'static str>,
outbound: Vec<&'static str>,
}
impl Default for Services {
fn default() -> Self {
Self {
inbound: vec![],
outbound: vec![ATOM_SERVICE],
}
}
}
#[derive(Serialize)]
@ -35,12 +75,25 @@ struct Metadata {
node_description: String,
}
impl Metadata {
fn new(config: &Config) -> Self {
Self {
node_name: config.instance_title.clone(),
node_description: config.instance_short_description.clone(),
}
}
}
fn has_open_registrations(config: &Config) -> bool {
config.registration.registration_type != RegistrationType::Invite
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct NodeInfo20 {
version: String,
software: Software,
protocols: Vec<String>,
version: &'static str,
software: Software20,
protocols: Vec<&'static str>,
services: Services,
open_registrations: bool,
usage: Usage,
@ -49,28 +102,40 @@ pub struct NodeInfo20 {
impl NodeInfo20 {
pub fn new(config: &Config, usage: Usage) -> Self {
let software = Software {
name: "mitra".to_string(),
version: MITRA_VERSION.to_string(),
};
let services = Services {
inbound: vec![],
outbound: vec!["atom1.0".to_string()],
};
let metadata = Metadata {
node_name: config.instance_title.clone(),
node_description: config.instance_short_description.clone(),
};
Self {
version: "2.0".to_string(),
software,
protocols: vec!["activitypub".to_string()],
services,
open_registrations:
config.registration.registration_type !=
RegistrationType::Invite,
version: "2.0",
software: Software20::default(),
protocols: vec![ACTIVITYPUB_PROTOCOL],
services: Services::default(),
open_registrations: has_open_registrations(config),
usage,
metadata,
metadata: Metadata::new(config),
}
}
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct NodeInfo21 {
version: &'static str,
software: Software21,
protocols: Vec<&'static str>,
services: Services,
open_registrations: bool,
usage: Usage,
metadata: Metadata,
}
impl NodeInfo21 {
pub fn new(config: &Config, usage: Usage) -> Self {
Self {
version: "2.1",
software: Software21::default(),
protocols: vec![ACTIVITYPUB_PROTOCOL],
services: Services::default(),
open_registrations: has_open_registrations(config),
usage,
metadata: Metadata::new(config),
}
}
}

View file

@ -11,22 +11,29 @@ use crate::webfinger::types::{
JsonResourceDescriptor,
};
use super::helpers::get_usage;
use super::types::NodeInfo20;
use super::types::{NodeInfo20, NodeInfo21};
#[get("/.well-known/nodeinfo")]
pub async fn get_nodeinfo(
pub async fn get_nodeinfo_jrd(
config: web::Data<Config>,
) -> Result<HttpResponse, HttpError> {
let nodeinfo_2_0_url = format!("{}/nodeinfo/2.0", config.instance_url());
let link = Link {
let nodeinfo_2_0_link = Link {
rel: "http://nodeinfo.diaspora.software/ns/schema/2.0".to_string(),
media_type: None,
href: Some(nodeinfo_2_0_url),
properties: Default::default(),
};
let nodeinfo_2_1_url = format!("{}/nodeinfo/2.1", config.instance_url());
let nodeinfo_2_1_link = Link {
rel: "http://nodeinfo.diaspora.software/ns/schema/2.1".to_string(),
media_type: None,
href: Some(nodeinfo_2_1_url),
properties: Default::default(),
};
let jrd = JsonResourceDescriptor {
subject: config.instance_url(),
links: vec![link],
links: vec![nodeinfo_2_0_link, nodeinfo_2_1_link],
};
let response = HttpResponse::Ok().json(jrd);
Ok(response)
@ -43,3 +50,15 @@ pub async fn get_nodeinfo_2_0(
let response = HttpResponse::Ok().json(nodeinfo);
Ok(response)
}
#[get("/nodeinfo/2.1")]
pub async fn get_nodeinfo_2_1(
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
) -> Result<HttpResponse, HttpError> {
let db_client = &**get_database_client(&db_pool).await?;
let usage = get_usage(db_client).await?;
let nodeinfo = NodeInfo21::new(&config, usage);
let response = HttpResponse::Ok().json(nodeinfo);
Ok(response)
}