Federate user deletion (#551)

* Federate user deletion

- When someone deletes their account
- When a local user is banned

Fixes #509

* cargo fmt
This commit is contained in:
Baptiste Gelez 2019-04-28 18:01:41 +01:00 committed by GitHub
parent 85aa0883c8
commit 787eb7f399
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 157 additions and 72 deletions

26
Cargo.lock generated
View file

@ -1777,7 +1777,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "plume"
version = "0.2.0"
version = "0.3.0"
dependencies = [
"activitypub 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"askama_escape 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1797,9 +1797,9 @@ dependencies = [
"lettre_email 0.9.0 (git+https://github.com/lettre/lettre?rev=c988b1760ad8179d9e7f3fb8594d2b86cf2a0a49)",
"multipart 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"plume-api 0.2.0",
"plume-common 0.2.0",
"plume-models 0.2.0",
"plume-api 0.3.0",
"plume-common 0.3.0",
"plume-models 0.3.0",
"rocket 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rocket_contrib 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rocket_csrf 0.1.0 (git+https://github.com/fdb-hiroshima/rocket_csrf?rev=4a72ea2ec716cb0b26188fb00bccf2ef7d1e031c)",
@ -1819,7 +1819,7 @@ dependencies = [
[[package]]
name = "plume-api"
version = "0.2.0"
version = "0.3.0"
dependencies = [
"canapi 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1828,18 +1828,18 @@ dependencies = [
[[package]]
name = "plume-cli"
version = "0.2.0"
version = "0.3.0"
dependencies = [
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"diesel 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
"plume-models 0.2.0",
"plume-models 0.3.0",
"rpassword 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "plume-common"
version = "0.2.0"
version = "0.3.0"
dependencies = [
"activitypub 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"activitystreams-derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1861,7 +1861,7 @@ dependencies = [
[[package]]
name = "plume-front"
version = "0.1.0"
version = "0.3.0"
dependencies = [
"gettext 0.3.0 (git+https://github.com/Plume-org/gettext/?rev=294c54d74c699fbc66502b480a37cc66c1daa7f3)",
"gettext-macros 0.4.0 (git+https://github.com/Plume-org/gettext-macros/?rev=a7c605f7edd6bfbfbfe7778026bfefd88d82db10)",
@ -1872,7 +1872,7 @@ dependencies = [
[[package]]
name = "plume-models"
version = "0.2.0"
version = "0.3.0"
dependencies = [
"activitypub 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ammonia 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1885,10 +1885,10 @@ dependencies = [
"guid-create 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl 0.10.19 (registry+https://github.com/rust-lang/crates.io-index)",
"plume-api 0.2.0",
"plume-common 0.2.0",
"plume-api 0.3.0",
"plume-common 0.3.0",
"reqwest 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)",
"rocket 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rocket_i18n 0.4.0 (git+https://github.com/Plume-org/rocket_i18n?rev=e922afa7c366038b3433278c03b1456b346074f2)",

View file

@ -53,6 +53,7 @@ pub fn inbox(ctx: &PlumeRocket, act: serde_json::Value) -> Result<InboxResult, E
.with::<User, Create, Post>()
.with::<User, Delete, Comment>()
.with::<User, Delete, Post>()
.with::<User, Delete, User>()
.with::<User, Follow, User>()
.with::<User, Like, Post>()
.with::<User, Undo, Reshare>()
@ -286,6 +287,34 @@ pub(crate) mod tests {
});
}
#[test]
fn delete_user() {
let r = rockets();
let conn = &*r.conn;
conn.test_transaction::<_, (), _>(|| {
let (_, users, _) = fill_database(&r);
let fail_act = json!({
"id": "https://plu.me/@/Admin#delete",
"actor": users[1].ap_url, // Not the same account
"object": users[0].ap_url,
"type": "Delete",
});
assert!(super::inbox(&r, fail_act).is_err());
let ok_act = json!({
"id": "https://plu.me/@/Admin#delete",
"actor": users[0].ap_url,
"object": users[0].ap_url,
"type": "Delete",
});
assert!(super::inbox(&r, ok_act).is_ok());
assert!(crate::users::User::get(conn, users[0].id).is_err());
Ok(())
});
}
#[test]
fn follow() {
let r = rockets();

View file

@ -1,5 +1,9 @@
use activitypub::{
actor::Person, collection::OrderedCollection, object::Image, Activity, CustomObject, Endpoint,
activity::Delete,
actor::Person,
collection::OrderedCollection,
object::{Image, Tombstone},
Activity, CustomObject, Endpoint,
};
use bcrypt;
use chrono::{NaiveDateTime, Utc};
@ -12,9 +16,9 @@ use openssl::{
};
use plume_common::activity_pub::{
ap_accept_header,
inbox::{AsActor, FromId},
inbox::{AsActor, AsObject, FromId},
sign::{gen_keypair, Signer},
ActivityStream, ApSignature, Id, IntoId, PublicKey,
ActivityStream, ApSignature, Id, IntoId, PublicKey, PUBLIC_VISIBILITY,
};
use plume_common::utils;
use reqwest::{
@ -632,6 +636,29 @@ impl User {
Ok(CustomPerson::new(actor, ap_signature))
}
pub fn delete_activity(&self, conn: &Connection) -> Result<Delete> {
let mut del = Delete::default();
let mut tombstone = Tombstone::default();
tombstone.object_props.set_id_string(self.ap_url.clone())?;
del.delete_props
.set_actor_link(Id::new(self.ap_url.clone()))?;
del.delete_props.set_object_object(tombstone)?;
del.object_props
.set_id_string(format!("{}#delete", self.ap_url))?;
del.object_props
.set_to_link_vec(vec![Id::new(PUBLIC_VISIBILITY)])?;
del.object_props.set_cc_link_vec(
self.get_followers(conn)?
.into_iter()
.map(|f| Id::new(f.ap_url))
.collect(),
)?;
Ok(del)
}
pub fn avatar_url(&self, conn: &Connection) -> String {
self.avatar_id
.and_then(|id| Media::get(conn, id).and_then(|m| m.url(conn)).ok())
@ -832,6 +859,19 @@ impl AsActor<&PlumeRocket> for User {
}
}
impl AsObject<User, Delete, &PlumeRocket> for User {
type Error = Error;
type Output = ();
fn activity(self, c: &PlumeRocket, actor: User, _id: &str) -> Result<()> {
if self.id == actor.id {
self.delete(&c.conn, &c.searcher).map(|_| ())
} else {
Err(Error::Unauthorized)
}
}
}
impl Signer for User {
type Error = Error;

View file

@ -265,10 +265,10 @@ msgid "Follow {}"
msgstr "اتبع"
#, fuzzy
msgid "Login to follow"
msgid "Log in to follow"
msgstr "قم بتسجيل الدخول قصد مشاركته"
msgid "Enter your full username to follow"
msgid "Enter your full username handle to follow"
msgstr ""
msgid "Edit your account"

View file

@ -262,10 +262,10 @@ msgstr "Писти Pluma {0}"
msgid "Follow {}"
msgstr ""
msgid "Login to follow"
msgid "Log in to follow"
msgstr ""
msgid "Enter your full username to follow"
msgid "Enter your full username handle to follow"
msgstr ""
msgid "Edit your account"

View file

@ -262,10 +262,10 @@ msgstr ""
msgid "Follow {}"
msgstr ""
msgid "Login to follow"
msgid "Log in to follow"
msgstr ""
msgid "Enter your full username to follow"
msgid "Enter your full username handle to follow"
msgstr ""
msgid "Edit your account"

View file

@ -264,10 +264,12 @@ msgstr "Beží na Plume {0}"
msgid "Follow {}"
msgstr "Následovat {}"
msgid "Login to follow"
#, fuzzy
msgid "Log in to follow"
msgstr "Pro následování se přihlášte"
msgid "Enter your full username to follow"
#, fuzzy
msgid "Enter your full username handle to follow"
msgstr "Pro následovaní zadejte své úplné uživatelské jméno"
msgid "Edit your account"

View file

@ -264,10 +264,10 @@ msgid "Follow {}"
msgstr "Folgen"
#, fuzzy
msgid "Login to follow"
msgid "Log in to follow"
msgstr "Um zu boosten, musst du eingeloggt sein"
msgid "Enter your full username to follow"
msgid "Enter your full username handle to follow"
msgstr ""
msgid "Edit your account"

View file

@ -262,10 +262,10 @@ msgstr ""
msgid "Follow {}"
msgstr ""
msgid "Login to follow"
msgid "Log in to follow"
msgstr ""
msgid "Enter your full username to follow"
msgid "Enter your full username handle to follow"
msgstr ""
msgid "Edit your account"

View file

@ -262,10 +262,10 @@ msgstr ""
msgid "Follow {}"
msgstr ""
msgid "Login to follow"
msgid "Log in to follow"
msgstr ""
msgid "Enter your full username to follow"
msgid "Enter your full username handle to follow"
msgstr ""
msgid "Edit your account"

View file

@ -264,10 +264,10 @@ msgid "Follow {}"
msgstr "Seguir"
#, fuzzy
msgid "Login to follow"
msgid "Log in to follow"
msgstr "Dejar de seguir"
msgid "Enter your full username to follow"
msgid "Enter your full username handle to follow"
msgstr ""
msgid "Edit your account"

View file

@ -265,10 +265,10 @@ msgid "Follow {}"
msgstr "Sabonner"
#, fuzzy
msgid "Login to follow"
msgid "Log in to follow"
msgstr "Connectez-vous pour partager"
msgid "Enter your full username to follow"
msgid "Enter your full username handle to follow"
msgstr ""
msgid "Edit your account"

View file

@ -265,10 +265,10 @@ msgid "Follow {}"
msgstr "Seguir"
#, fuzzy
msgid "Login to follow"
msgid "Log in to follow"
msgstr "Conéctese para promover"
msgid "Enter your full username to follow"
msgid "Enter your full username handle to follow"
msgstr ""
msgid "Edit your account"

View file

@ -264,10 +264,10 @@ msgstr "Plume {0} का इस्तेमाल कर रहे हैं"
msgid "Follow {}"
msgstr ""
msgid "Login to follow"
msgid "Log in to follow"
msgstr ""
msgid "Enter your full username to follow"
msgid "Enter your full username handle to follow"
msgstr ""
msgid "Edit your account"

View file

@ -263,10 +263,10 @@ msgstr ""
msgid "Follow {}"
msgstr ""
msgid "Login to follow"
msgid "Log in to follow"
msgstr ""
msgid "Enter your full username to follow"
msgid "Enter your full username handle to follow"
msgstr ""
msgid "Edit your account"

View file

@ -264,10 +264,10 @@ msgid "Follow {}"
msgstr "Segui"
#, fuzzy
msgid "Login to follow"
msgid "Log in to follow"
msgstr "Accedi per boostare"
msgid "Enter your full username to follow"
msgid "Enter your full username handle to follow"
msgstr ""
msgid "Edit your account"

View file

@ -267,10 +267,10 @@ msgid "Follow {}"
msgstr "フォロー"
#, fuzzy
msgid "Login to follow"
msgid "Log in to follow"
msgstr "ブーストするにはログインしてください"
msgid "Enter your full username to follow"
msgid "Enter your full username handle to follow"
msgstr ""
msgid "Edit your account"

View file

@ -274,10 +274,10 @@ msgid "Follow {}"
msgstr "Følg"
#, fuzzy
msgid "Login to follow"
msgid "Log in to follow"
msgstr "Logg inn"
msgid "Enter your full username to follow"
msgid "Enter your full username handle to follow"
msgstr ""
msgid "Edit your account"

View file

@ -264,10 +264,11 @@ msgstr "Działa na Plume {0}"
msgid "Follow {}"
msgstr "Obserwuj {}"
msgid "Login to follow"
msgid "Log in to follow"
msgstr ""
msgid "Enter your full username to follow"
#, fuzzy
msgid "Enter your full username handle to follow"
msgstr "Wpisz swoją pełną nazwę użytkownika, do naśladowania"
msgid "Edit your account"

View file

@ -256,10 +256,10 @@ msgstr ""
msgid "Follow {}"
msgstr ""
msgid "Login to follow"
msgid "Log in to follow"
msgstr ""
msgid "Enter your full username to follow"
msgid "Enter your full username handle to follow"
msgstr ""
msgid "Edit your account"

View file

@ -266,10 +266,10 @@ msgid "Follow {}"
msgstr "Seguir"
#, fuzzy
msgid "Login to follow"
msgid "Log in to follow"
msgstr "Entrar para gostar"
msgid "Enter your full username to follow"
msgid "Enter your full username handle to follow"
msgstr ""
msgid "Edit your account"

View file

@ -263,10 +263,10 @@ msgstr ""
msgid "Follow {}"
msgstr ""
msgid "Login to follow"
msgid "Log in to follow"
msgstr ""
msgid "Enter your full username to follow"
msgid "Enter your full username handle to follow"
msgstr ""
msgid "Edit your account"

View file

@ -266,10 +266,10 @@ msgid "Follow {}"
msgstr "Подписаться"
#, fuzzy
msgid "Login to follow"
msgid "Log in to follow"
msgstr "Войдите, чтобы продвигать посты"
msgid "Enter your full username to follow"
msgid "Enter your full username handle to follow"
msgstr ""
msgid "Edit your account"

View file

@ -264,10 +264,12 @@ msgstr "Beží na Plume {0}"
msgid "Follow {}"
msgstr "Následuj {}"
msgid "Login to follow"
#, fuzzy
msgid "Log in to follow"
msgstr "Pre následovanie sa prihlás"
msgid "Enter your full username to follow"
#, fuzzy
msgid "Enter your full username handle to follow"
msgstr "Zadaj svoju prezývku v úplnosti, aby si následoval/a"
msgid "Edit your account"

View file

@ -263,10 +263,10 @@ msgstr ""
msgid "Follow {}"
msgstr ""
msgid "Login to follow"
msgid "Log in to follow"
msgstr ""
msgid "Enter your full username to follow"
msgid "Enter your full username handle to follow"
msgstr ""
msgid "Edit your account"

View file

@ -262,10 +262,10 @@ msgstr ""
msgid "Follow {}"
msgstr ""
msgid "Login to follow"
msgid "Log in to follow"
msgstr ""
msgid "Enter your full username to follow"
msgid "Enter your full username handle to follow"
msgstr ""
msgid "Edit your account"

View file

@ -8,14 +8,13 @@ use serde_json;
use validator::{Validate, ValidationErrors};
use inbox;
use plume_common::activity_pub::inbox::FromId;
use plume_common::activity_pub::{broadcast, inbox::FromId};
use plume_models::{
admin::Admin, comments::Comment, db_conn::DbConn, headers::Headers, instance::*, posts::Post,
safe_string::SafeString, users::User, Error, PlumeRocket, CONFIG,
};
use routes::{errors::ErrorPage, rocket_uri_macro_static_files, Page};
use template_utils::Ructe;
use Searcher;
#[get("/")]
pub fn index(conn: DbConn, user: Option<User>, intl: I18n) -> Result<Ructe, ErrorPage> {
@ -197,14 +196,20 @@ pub fn admin_users(
}
#[post("/admin/users/<id>/ban")]
pub fn ban(
_admin: Admin,
conn: DbConn,
id: i32,
searcher: Searcher,
) -> Result<Redirect, ErrorPage> {
if let Ok(u) = User::get(&*conn, id) {
u.delete(&*conn, &searcher)?;
pub fn ban(_admin: Admin, id: i32, rockets: PlumeRocket) -> Result<Redirect, ErrorPage> {
if let Ok(u) = User::get(&*rockets.conn, id) {
u.delete(&*rockets.conn, &rockets.searcher)?;
if Instance::get_local(&*rockets.conn)
.map(|i| u.instance_id == i.id)
.unwrap_or(false)
{
let target = User::one_by_instance(&*rockets.conn)?;
let delete_act = u.delete_activity(&*rockets.conn)?;
rockets
.worker
.execute(move || broadcast(&u, delete_act, target));
}
}
Ok(Redirect::to(uri!(admin_users: page = _)))
}

View file

@ -394,6 +394,12 @@ pub fn delete(
if user.id == account.id {
account.delete(&*rockets.conn, &rockets.searcher)?;
let target = User::one_by_instance(&*rockets.conn)?;
let delete_act = account.delete_activity(&*rockets.conn)?;
rockets
.worker
.execute(move || broadcast(&account, delete_act, target));
if let Some(cookie) = cookies.get_private(AUTH_COOKIE) {
cookies.remove_private(cookie);
}