Add support for pulling a pleroma admin

This commit is contained in:
asonix 2021-02-11 13:41:03 -06:00
parent 6b7f0f2b63
commit 1311f92b6c
7 changed files with 124 additions and 9 deletions

2
Cargo.lock generated
View file

@ -1761,7 +1761,7 @@ checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581"
[[package]]
name = "relay"
version = "0.2.6"
version = "0.2.7"
dependencies = [
"activitystreams",
"activitystreams-ext",

View file

@ -1,7 +1,7 @@
[package]
name = "relay"
description = "A simple activitypub relay"
version = "0.2.6"
version = "0.2.7"
authors = ["asonix <asonix@asonix.dog>"]
license-file = "LICENSE"
readme = "README.md"

View file

@ -691,6 +691,6 @@ mod tests {
{
let db =
Db::build_inner(true, sled::Config::new().temporary(true).open().unwrap()).unwrap();
actix_rt::System::new("test").block_on((f)(db));
actix_rt::System::new().block_on((f)(db));
}
}

96
src/jobs/contact.rs Normal file
View file

@ -0,0 +1,96 @@
use crate::{apub::AcceptedActors, jobs::JobState};
use activitystreams::{object::Image, prelude::*, url::Url};
use anyhow::Error;
use background_jobs::ActixJob;
use std::{future::Future, pin::Pin};
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
pub(crate) struct QueryContact {
actor_id: Url,
contact_id: Url,
}
impl QueryContact {
pub(crate) fn new(actor_id: Url, contact_id: Url) -> Self {
QueryContact {
actor_id,
contact_id,
}
}
async fn perform(self, state: JobState) -> Result<(), Error> {
let contact_outdated = state
.node_cache
.is_contact_outdated(self.actor_id.clone())
.await;
if !contact_outdated {
return Ok(());
}
let contact = state
.requests
.fetch::<AcceptedActors>(self.contact_id.as_str())
.await?;
let username = contact.preferred_username();
let display_name = contact
.name()
.and_then(|name| name.as_one().and_then(|s| s.as_xsd_string()));
let url = contact.url().and_then(|url| url.as_single_id());
let avatar = contact
.icon()
.and_then(|one_or_many| one_or_many.as_one())
.and_then(|any_base| Image::from_any_base(any_base.clone()).ok()?)
.and_then(|image| {
image
.url()
.and_then(|url| url.as_single_id())
.map(|url| url.to_owned())
});
let optioned = || {
let username = username?;
let display_name = display_name?;
let url = url?;
let avatar = avatar?;
Some(state.node_cache.set_contact(
self.actor_id.clone(),
username.to_owned(),
display_name.to_owned(),
url.to_owned(),
avatar.to_owned(),
))
};
if let Some(fut) = (optioned)() {
fut.await?;
}
Ok(())
}
}
impl ActixJob for QueryContact {
type State = JobState;
type Future = Pin<Box<dyn Future<Output = Result<(), Error>>>>;
const NAME: &'static str = "relay::jobs::QueryContact";
fn run(self, state: Self::State) -> Self::Future {
Box::pin(self.perform(state))
}
}
#[cfg(test)]
mod tests {
use crate::apub::AcceptedActors;
const HYNET_ADMIN: &'static str = r#"{"@context":["https://www.w3.org/ns/activitystreams","https://soc.hyena.network/schemas/litepub-0.1.jsonld",{"@language":"und"}],"alsoKnownAs":[],"attachment":[{"name":"Website","type":"PropertyValue","value":"https://hyena.network/"},{"name":"Services","type":"PropertyValue","value":"Pleroma, Invidious, SearX, XMPP"},{"name":"CW","type":"PropertyValue","value":"all long posts"}],"capabilities":{"acceptsChatMessages":true},"discoverable":true,"endpoints":{"oauthAuthorizationEndpoint":"https://soc.hyena.network/oauth/authorize","oauthRegistrationEndpoint":"https://soc.hyena.network/api/v1/apps","oauthTokenEndpoint":"https://soc.hyena.network/oauth/token","sharedInbox":"https://soc.hyena.network/inbox","uploadMedia":"https://soc.hyena.network/api/ap/upload_media"},"followers":"https://soc.hyena.network/users/HyNET/followers","following":"https://soc.hyena.network/users/HyNET/following","icon":{"type":"Image","url":"https://soc.hyena.network/media/ab149b1e0196ffdbecc6830c7f6f1a14dd8d8408ec7db0f1e8ad9d40e600ea73.gif"},"id":"https://soc.hyena.network/users/HyNET","image":{"type":"Image","url":"https://soc.hyena.network/media/12ba78d3015e13aa65ac4e106e574dd7bf959614585f10ce85de40e0148da677.png"},"inbox":"https://soc.hyena.network/users/HyNET/inbox","manuallyApprovesFollowers":false,"name":"HyNET Announcement System :glider:","outbox":"https://soc.hyena.network/users/HyNET/outbox","preferredUsername":"HyNET","publicKey":{"id":"https://soc.hyena.network/users/HyNET#main-key","owner":"https://soc.hyena.network/users/HyNET","publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyF74womumWRhR7RW4Q6a\n2+Av/Ue8QHiKwjQARJEakbKnKgkI5FRFVVOfMiYVJp/juNt4GLgK15panBqJa9Yt\nWACiHQjBd2yVI5tIHiae0uBj5SdUVuduoycVLG0lpJsg12p8m/vL1oaeLqehTqa6\nsYplQh1GCLet0cUdn/66Cj2pAPD3V7Bz3VnG+oyXIsGQbBB8RHnWhFH8b0qQOyur\nJRAB8aye6QAL2sQbfISM2lycWzNeIHkqsUb7FdqdhQ+Ze0rETRGDkOO2Qvpg0hQm\n6owMsHnHA/DzyOHLy6Yf+I3OUlBC/P1SSAKwORsifFDXL322AEqoDi5ZpwzG9m5z\nAQIDAQAB\n-----END PUBLIC KEY-----\n\n"},"summary":"Ran by <span class=\"h-card\"><a class=\"u-url mention\" data-user=\"9s8j4AHGt3ED0P0b6e\" href=\"https://soc.hyena.network/users/mel\" rel=\"ugc\">@<span>mel</span></a></span> :adm1::adm2: <br/>For direct help with the service, send <span class=\"h-card\"><a class=\"u-url mention\" data-user=\"9s8j4AHGt3ED0P0b6e\" href=\"https://soc.hyena.network/users/mel\" rel=\"ugc\">@<span>mel</span></a></span> a message.","tag":[{"icon":{"type":"Image","url":"https://soc.hyena.network/emoji/Signs/adm1.png"},"id":"https://soc.hyena.network/emoji/Signs/adm1.png","name":":adm1:","type":"Emoji","updated":"1970-01-01T00:00:00Z"},{"icon":{"type":"Image","url":"https://soc.hyena.network/emoji/Signs/adm2.png"},"id":"https://soc.hyena.network/emoji/Signs/adm2.png","name":":adm2:","type":"Emoji","updated":"1970-01-01T00:00:00Z"},{"icon":{"type":"Image","url":"https://soc.hyena.network/emoji/misc/glider.png"},"id":"https://soc.hyena.network/emoji/misc/glider.png","name":":glider:","type":"Emoji","updated":"1970-01-01T00:00:00Z"}],"type":"Service","url":"https://soc.hyena.network/users/HyNET"}"#;
#[test]
fn parse_hynet() {
serde_json::from_str::<AcceptedActors>(HYNET_ADMIN).unwrap();
}
}

View file

@ -14,9 +14,7 @@ pub(crate) struct QueryInstance {
impl QueryInstance {
pub(crate) fn new(actor_id: Url) -> Self {
QueryInstance {
actor_id: actor_id.into(),
}
QueryInstance { actor_id }
}
async fn perform(self, state: JobState) -> Result<(), Error> {

View file

@ -1,5 +1,6 @@
pub mod apub;
mod cache_media;
mod contact;
mod deliver;
mod deliver_many;
mod instance;
@ -7,8 +8,8 @@ mod nodeinfo;
mod process_listeners;
pub(crate) use self::{
cache_media::CacheMedia, deliver::Deliver, deliver_many::DeliverMany, instance::QueryInstance,
nodeinfo::QueryNodeinfo,
cache_media::CacheMedia, contact::QueryContact, deliver::Deliver, deliver_many::DeliverMany,
instance::QueryInstance, nodeinfo::QueryNodeinfo,
};
use crate::{
@ -56,6 +57,7 @@ pub(crate) fn create_workers(
.register::<QueryInstance>()
.register::<Listeners>()
.register::<CacheMedia>()
.register::<QueryContact>()
.register::<apub::Announce>()
.register::<apub::Follow>()
.register::<apub::Forward>()

View file

@ -1,4 +1,4 @@
use crate::jobs::JobState;
use crate::jobs::{JobState, QueryContact};
use activitystreams::url::Url;
use anyhow::Error;
use background_jobs::ActixJob;
@ -50,6 +50,15 @@ impl QueryNodeinfo {
nodeinfo.open_registrations,
)
.await?;
if let Some(accounts) = nodeinfo.staff_accounts {
if let Some(contact_id) = accounts.get(0) {
state
.job_server
.queue(QueryContact::new(self.actor_id, contact_id.clone()))?;
}
}
Ok(())
}
}
@ -73,6 +82,7 @@ struct Nodeinfo {
software: Software,
open_registrations: bool,
staff_accounts: Option<Vec<Url>>,
}
#[derive(serde::Deserialize)]
@ -181,11 +191,20 @@ mod tests {
const BANANA_DOG: &'static str = r#"{"links":[{"rel":"http://nodeinfo.diaspora.software/ns/schema/2.0","href":"https://banana.dog/nodeinfo/2.0"},{"rel":"http://nodeinfo.diaspora.software/ns/schema/2.1","href":"https://banana.dog/nodeinfo/2.1"}]}"#;
const ASONIX_DOG: &'static str = r#"{"links":[{"rel":"http://nodeinfo.diaspora.software/ns/schema/2.0","href":"https://asonix.dog/nodeinfo/2.0"}]}"#;
const RELAY_ASONIX_DOG: &'static str = r#"{"links":[{"rel":"http://nodeinfo.diaspora.software/ns/schema/2.0","href":"https://relay.asonix.dog/nodeinfo/2.0.json"}]}"#;
const HYNET: &'static str = r#"{"links":[{"href":"https://soc.hyena.network/nodeinfo/2.0.json","rel":"http://nodeinfo.diaspora.software/ns/schema/2.0"},{"href":"https://soc.hyena.network/nodeinfo/2.1.json","rel":"http://nodeinfo.diaspora.software/ns/schema/2.1"}]}"#;
const BANANA_DOG_NODEINFO: &'static str = r#"{"version":"2.1","software":{"name":"corgidon","version":"3.1.3+corgi","repository":"https://github.com/msdos621/corgidon"},"protocols":["activitypub"],"usage":{"users":{"total":203,"activeMonth":115,"activeHalfyear":224},"localPosts":28856},"openRegistrations":true,"metadata":{"nodeName":"Banana.dog","nodeDescription":"\u003c/p\u003e\r\n\u003cp\u003e\r\nOfficially endorsed by \u003ca href=\"https://mastodon.social/@Gargron/100059130444127703\"\u003e@Gargron\u003c/a\u003e as a joke instance (along with \u003ca href=\"https://freedom.horse/about\"\u003efreedom.horse\u003c/a\u003e). Things that make banana.dog unique as an instance.\r\n\u003c/p\u003e\r\n\u003cul\u003e\r\n\u003cli\u003eFederates with TOR servers\u003c/li\u003e\r\n\u003cli\u003eStays up to date, often running newest mastodon code\u003c/li\u003e\r\n\u003cli\u003eUnique color scheme\u003c/li\u003e\r\n\u003cli\u003eA thorough set of rules\u003c/li\u003e\r\n\u003cli\u003eA BananaDogInc company. Visit our other sites sites including \u003ca href=\"https://betamax.video\"\u003ebetaMax.video\u003c/a\u003e, \u003ca href=\"https://psychicdebugging.com\"\u003epsychicdebugging\u003c/a\u003e and \u003ca href=\"https://somebody.once.told.me.the.world.is.gonnaroll.me/\"\u003egonnaroll\u003c/a\u003e\u003c/li\u003e\r\n\u003c/ul\u003e\r\n\u003cp\u003e\r\n\u003cem\u003eWho we are looking for:\u003c/em\u003e\r\nThis instance only allows senior toot engineers. If you have at least 10+ years of mastodon experience please apply here (https://banana.dog). We are looking for rockstar ninja rocket scientists and we offer unlimited PTO as well as a fully stocked snack bar (with soylent). We are a lean, agile, remote friendly mastodon startup that pays in the bottom 25% for senior tooters. All new members get equity via an innovative ICO call BananaCoin.\r\n\u003c/p\u003e\r\n\u003cp\u003e\r\n\u003cem\u003eThe interview process\u003c/em\u003e\r\nTo join we have a take home exam that involves you writing several hundred toots that we can use to screen you. We will then throw these away during your interview so that we can do a technical screening where we use a whiteboard to evaluate your ability to re-toot memes and shitpost in front of a panel. This panel will be composed of senior tooters who are all 30 year old cis white males (coincidence).\r\n\u003c/p\u003e\r\n\u003cp\u003e\r\n\u003cem\u003eHere are the reasons you may want to join:\u003c/em\u003e\r\nWe are an agile tooting startup (a tootup). That means for every senior tooter we have a designer, a UX person, a product manager, project manager and scrum master. We meet for 15min every day and plan twice a week in a 3 hour meeting but its cool because you get lunch and have to attend. Our tooters love it, I would know if they didnt since we all have standing desks in an open office layouts d can hear everything!\r\n\u003c/p\u003e\r\n\u003cp\u003e\r\n\u003ca href=\"https://www.patreon.com/bePatron?u=178864\" data-patreon-widget-type=\"become-patron-button\"\u003eSupport our sites on Patreon\u003c/a\u003e\r\n\u003c/p\u003e\r\n\u003cp\u003e","nodeTerms":"","siteContactEmail":"corgi@banana.dog","domainCount":5841,"features":["mastodon_api","mastodon_api_streaming"],"invitesEnabled":true,"federation":{"rejectMedia":[],"rejectReports":[],"silence":[],"suspend":[]}},"services":{"outbound":[],"inbound":[]}}"#;
const ASONIX_DOG_NODEINFO: &'static str = r#"{"version":"2.0","software":{"name":"mastodon","version":"3.1.3-asonix-changes"},"protocols":["activitypub"],"usage":{"users":{"total":19,"activeMonth":5,"activeHalfyear":5},"localPosts":43036},"openRegistrations":false}"#;
const RELAY_ASONIX_DOG_NODEINFO: &'static str = r#"{"version":"2.0","software":{"name":"aoderelay","version":"v0.1.0-master"},"protocols":["activitypub"],"services":{"inbound":[],"outbound":[]},"openRegistrations":false,"usage":{"users":{"total":1,"activeHalfyear":1,"activeMonth":1},"localPosts":0,"localComments":0},"metadata":{"peers":[],"blocks":[]}}"#;
const HYNET_NODEINFO: &'static str = r#"{"metadata":{"accountActivationRequired":true,"features":["pleroma_api","mastodon_api","mastodon_api_streaming","polls","pleroma_explicit_addressing","shareable_emoji_packs","multifetch","pleroma:api/v1/notifications:include_types_filter","media_proxy","chat","relay","safe_dm_mentions","pleroma_emoji_reactions","pleroma_chat_messages"],"federation":{"enabled":true,"exclusions":false,"mrf_policies":["SimplePolicy","EnsureRePrepended"],"mrf_simple":{"accept":[],"avatar_removal":[],"banner_removal":[],"federated_timeline_removal":["botsin.space","humblr.social","switter.at","kinkyelephant.com","mstdn.foxfam.club","dajiaweibo.com"],"followers_only":[],"media_nsfw":["mstdn.jp","wxw.moe","knzk.me","anime.website","pl.nudie.social","neckbeard.xyz","baraag.net","pawoo.net","vipgirlfriend.xxx","humblr.social","switter.at","kinkyelephant.com","sinblr.com","kinky.business","rubber.social"],"media_removal":[],"reject":["gab.com","search.fedi.app","kiwifarms.cc","pawoo.net","2hu.club","gameliberty.club","loli.estate","shitasstits.life","social.homunyan.com","club.super-niche.club","vampire.estate","weeaboo.space","wxw.moe","youkai.town","kowai.youkai.town","preteengirls.biz","vipgirlfriend.xxx","social.myfreecams.com","pleroma.rareome.ga","ligma.pro","nnia.space","dickkickextremist.xyz","freespeechextremist.com","m.gretaoto.ca","7td.org","pl.smuglo.li","pleroma.hatthieves.es","jojo.singleuser.club","anime.website","rage.lol","shitposter.club"],"reject_deletes":[],"report_removal":[]},"quarantined_instances":["freespeechextremist.com","spinster.xyz"]},"fieldsLimits":{"maxFields":10,"maxRemoteFields":20,"nameLength":512,"valueLength":2048},"invitesEnabled":true,"mailerEnabled":true,"nodeDescription":"All the cackling for your hyaenid needs.","nodeName":"HyNET Social","pollLimits":{"max_expiration":31536000,"max_option_chars":200,"max_options":20,"min_expiration":0},"postFormats":["text/plain","text/html","text/markdown","text/bbcode"],"private":false,"restrictedNicknames":[".well-known","~","about","activities","api","auth","check_password","dev","friend-requests","inbox","internal","main","media","nodeinfo","notice","oauth","objects","ostatus_subscribe","pleroma","proxy","push","registration","relay","settings","status","tag","user-search","user_exists","users","web","verify_credentials","update_credentials","relationships","search","confirmation_resend","mfa"],"skipThreadContainment":true,"staffAccounts":["https://soc.hyena.network/users/HyNET","https://soc.hyena.network/users/mel"],"suggestions":{"enabled":false},"uploadLimits":{"avatar":2000000,"background":4000000,"banner":4000000,"general":10000000}},"openRegistrations":true,"protocols":["activitypub"],"services":{"inbound":[],"outbound":[]},"software":{"name":"pleroma","version":"2.2.50-724-gf917285b-develop+HyNET-prod"},"usage":{"localPosts":3444,"users":{"total":19}},"version":"2.0"}"#;
#[test]
fn hyena_network() {
is_supported(HYNET);
de::<Nodeinfo>(HYNET_NODEINFO);
}
#[test]
fn banana_dog() {
is_supported(BANANA_DOG);