Merge branch 'validate-attributed-to' into main
This commit is contained in:
commit
aa33c8e7d3
@ -59,6 +59,10 @@
|
|||||||
- Don't show boosts and likes for "all" and "local" in timelines (#781)
|
- Don't show boosts and likes for "all" and "local" in timelines (#781)
|
||||||
- Fix liking and boosting posts on remote instances (#762)
|
- Fix liking and boosting posts on remote instances (#762)
|
||||||
|
|
||||||
|
### Security
|
||||||
|
|
||||||
|
- Validate spoofing of Create activity
|
||||||
|
|
||||||
## [0.4.0] - 2019-12-23
|
## [0.4.0] - 2019-12-23
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
@ -164,6 +164,11 @@ where
|
|||||||
Some(x) => x,
|
Some(x) => x,
|
||||||
None => return Inbox::NotHandled(ctx, act, InboxError::InvalidActor(None)),
|
None => return Inbox::NotHandled(ctx, act, InboxError::InvalidActor(None)),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if Self::is_spoofed_activity(&actor_id, &act) {
|
||||||
|
return Inbox::NotHandled(ctx, act, InboxError::InvalidObject(None));
|
||||||
|
}
|
||||||
|
|
||||||
// Transform this actor to a model (see FromId for details about the from_id function)
|
// Transform this actor to a model (see FromId for details about the from_id function)
|
||||||
let actor = match A::from_id(
|
let actor = match A::from_id(
|
||||||
ctx,
|
ctx,
|
||||||
@ -222,6 +227,29 @@ where
|
|||||||
Inbox::Failed(err) => Err(err),
|
Inbox::Failed(err) => Err(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_spoofed_activity(actor_id: &str, act: &serde_json::Value) -> bool {
|
||||||
|
use serde_json::Value::{Array, Object, String};
|
||||||
|
|
||||||
|
if act["type"] != String("Create".to_string()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let attributed_to = act["object"].get("attributedTo");
|
||||||
|
if attributed_to.is_none() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let attributed_to = attributed_to.unwrap();
|
||||||
|
match attributed_to {
|
||||||
|
Array(v) => v.iter().all(|i| match i {
|
||||||
|
String(s) => s != actor_id,
|
||||||
|
Object(obj) => obj.get("id").map_or(true, |s| s != actor_id),
|
||||||
|
_ => false,
|
||||||
|
}),
|
||||||
|
String(s) => s != actor_id,
|
||||||
|
Object(obj) => obj.get("id").map_or(true, |s| s != actor_id),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the ActivityPub ID of a JSON value.
|
/// Get the ActivityPub ID of a JSON value.
|
||||||
|
@ -173,6 +173,97 @@ pub(crate) mod tests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn spoof_comment() {
|
||||||
|
let r = rockets();
|
||||||
|
let conn = &*r.conn;
|
||||||
|
conn.test_transaction::<_, (), _>(|| {
|
||||||
|
let (posts, users, _) = fill_database(&r);
|
||||||
|
let act = json!({
|
||||||
|
"id": "https://plu.me/comment/1/activity",
|
||||||
|
"actor": users[0].ap_url,
|
||||||
|
"object": {
|
||||||
|
"type": "Note",
|
||||||
|
"id": "https://plu.me/comment/1",
|
||||||
|
"attributedTo": users[1].ap_url,
|
||||||
|
"inReplyTo": posts[0].ap_url,
|
||||||
|
"content": "Hello.",
|
||||||
|
"to": [plume_common::activity_pub::PUBLIC_VISIBILITY]
|
||||||
|
},
|
||||||
|
"type": "Create",
|
||||||
|
});
|
||||||
|
|
||||||
|
assert!(matches!(
|
||||||
|
super::inbox(&r, act.clone()),
|
||||||
|
Err(super::Error::Inbox(
|
||||||
|
box plume_common::activity_pub::inbox::InboxError::InvalidObject(_),
|
||||||
|
))
|
||||||
|
));
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn spoof_comment_by_object_with_id() {
|
||||||
|
let r = rockets();
|
||||||
|
let conn = &*r.conn;
|
||||||
|
conn.test_transaction::<_, (), _>(|| {
|
||||||
|
let (posts, users, _) = fill_database(&r);
|
||||||
|
let act = json!({
|
||||||
|
"id": "https://plu.me/comment/1/activity",
|
||||||
|
"actor": users[0].ap_url,
|
||||||
|
"object": {
|
||||||
|
"type": "Note",
|
||||||
|
"id": "https://plu.me/comment/1",
|
||||||
|
"attributedTo": {
|
||||||
|
"id": users[1].ap_url
|
||||||
|
},
|
||||||
|
"inReplyTo": posts[0].ap_url,
|
||||||
|
"content": "Hello.",
|
||||||
|
"to": [plume_common::activity_pub::PUBLIC_VISIBILITY]
|
||||||
|
},
|
||||||
|
"type": "Create",
|
||||||
|
});
|
||||||
|
|
||||||
|
assert!(matches!(
|
||||||
|
super::inbox(&r, act.clone()),
|
||||||
|
Err(super::Error::Inbox(
|
||||||
|
box plume_common::activity_pub::inbox::InboxError::InvalidObject(_),
|
||||||
|
))
|
||||||
|
));
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn spoof_comment_by_object_without_id() {
|
||||||
|
let r = rockets();
|
||||||
|
let conn = &*r.conn;
|
||||||
|
conn.test_transaction::<_, (), _>(|| {
|
||||||
|
let (posts, users, _) = fill_database(&r);
|
||||||
|
let act = json!({
|
||||||
|
"id": "https://plu.me/comment/1/activity",
|
||||||
|
"actor": users[0].ap_url,
|
||||||
|
"object": {
|
||||||
|
"type": "Note",
|
||||||
|
"id": "https://plu.me/comment/1",
|
||||||
|
"attributedTo": {},
|
||||||
|
"inReplyTo": posts[0].ap_url,
|
||||||
|
"content": "Hello.",
|
||||||
|
"to": [plume_common::activity_pub::PUBLIC_VISIBILITY]
|
||||||
|
},
|
||||||
|
"type": "Create",
|
||||||
|
});
|
||||||
|
|
||||||
|
assert!(matches!(
|
||||||
|
super::inbox(&r, act.clone()),
|
||||||
|
Err(super::Error::Inbox(
|
||||||
|
box plume_common::activity_pub::inbox::InboxError::InvalidObject(_),
|
||||||
|
))
|
||||||
|
));
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn create_post() {
|
fn create_post() {
|
||||||
let r = rockets();
|
let r = rockets();
|
||||||
@ -214,6 +305,117 @@ pub(crate) mod tests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn spoof_post() {
|
||||||
|
let r = rockets();
|
||||||
|
let conn = &*r.conn;
|
||||||
|
conn.test_transaction::<_, (), _>(|| {
|
||||||
|
let (_, users, blogs) = fill_database(&r);
|
||||||
|
let act = json!({
|
||||||
|
"id": "https://plu.me/comment/1/activity",
|
||||||
|
"actor": users[0].ap_url,
|
||||||
|
"object": {
|
||||||
|
"type": "Article",
|
||||||
|
"id": "https://plu.me/~/Blog/my-article",
|
||||||
|
"attributedTo": [users[1].ap_url, blogs[0].ap_url],
|
||||||
|
"content": "Hello.",
|
||||||
|
"name": "My Article",
|
||||||
|
"summary": "Bye.",
|
||||||
|
"source": {
|
||||||
|
"content": "Hello.",
|
||||||
|
"mediaType": "text/markdown"
|
||||||
|
},
|
||||||
|
"published": "2014-12-12T12:12:12Z",
|
||||||
|
"to": [plume_common::activity_pub::PUBLIC_VISIBILITY]
|
||||||
|
},
|
||||||
|
"type": "Create",
|
||||||
|
});
|
||||||
|
|
||||||
|
assert!(matches!(
|
||||||
|
super::inbox(&r, act.clone()),
|
||||||
|
Err(super::Error::Inbox(
|
||||||
|
box plume_common::activity_pub::inbox::InboxError::InvalidObject(_),
|
||||||
|
))
|
||||||
|
));
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn spoof_post_by_object_with_id() {
|
||||||
|
let r = rockets();
|
||||||
|
let conn = &*r.conn;
|
||||||
|
conn.test_transaction::<_, (), _>(|| {
|
||||||
|
let (_, users, blogs) = fill_database(&r);
|
||||||
|
let act = json!({
|
||||||
|
"id": "https://plu.me/comment/1/activity",
|
||||||
|
"actor": users[0].ap_url,
|
||||||
|
"object": {
|
||||||
|
"type": "Article",
|
||||||
|
"id": "https://plu.me/~/Blog/my-article",
|
||||||
|
"attributedTo": [
|
||||||
|
{"id": users[1].ap_url},
|
||||||
|
blogs[0].ap_url
|
||||||
|
],
|
||||||
|
"content": "Hello.",
|
||||||
|
"name": "My Article",
|
||||||
|
"summary": "Bye.",
|
||||||
|
"source": {
|
||||||
|
"content": "Hello.",
|
||||||
|
"mediaType": "text/markdown"
|
||||||
|
},
|
||||||
|
"published": "2014-12-12T12:12:12Z",
|
||||||
|
"to": [plume_common::activity_pub::PUBLIC_VISIBILITY]
|
||||||
|
},
|
||||||
|
"type": "Create",
|
||||||
|
});
|
||||||
|
|
||||||
|
assert!(matches!(
|
||||||
|
super::inbox(&r, act.clone()),
|
||||||
|
Err(super::Error::Inbox(
|
||||||
|
box plume_common::activity_pub::inbox::InboxError::InvalidObject(_),
|
||||||
|
))
|
||||||
|
));
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn spoof_post_by_object_without_id() {
|
||||||
|
let r = rockets();
|
||||||
|
let conn = &*r.conn;
|
||||||
|
conn.test_transaction::<_, (), _>(|| {
|
||||||
|
let (_, users, blogs) = fill_database(&r);
|
||||||
|
let act = json!({
|
||||||
|
"id": "https://plu.me/comment/1/activity",
|
||||||
|
"actor": users[0].ap_url,
|
||||||
|
"object": {
|
||||||
|
"type": "Article",
|
||||||
|
"id": "https://plu.me/~/Blog/my-article",
|
||||||
|
"attributedTo": [{}, blogs[0].ap_url],
|
||||||
|
"content": "Hello.",
|
||||||
|
"name": "My Article",
|
||||||
|
"summary": "Bye.",
|
||||||
|
"source": {
|
||||||
|
"content": "Hello.",
|
||||||
|
"mediaType": "text/markdown"
|
||||||
|
},
|
||||||
|
"published": "2014-12-12T12:12:12Z",
|
||||||
|
"to": [plume_common::activity_pub::PUBLIC_VISIBILITY]
|
||||||
|
},
|
||||||
|
"type": "Create",
|
||||||
|
});
|
||||||
|
|
||||||
|
assert!(matches!(
|
||||||
|
super::inbox(&r, act.clone()),
|
||||||
|
Err(super::Error::Inbox(
|
||||||
|
box plume_common::activity_pub::inbox::InboxError::InvalidObject(_),
|
||||||
|
))
|
||||||
|
));
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn delete_comment() {
|
fn delete_comment() {
|
||||||
use crate::comments::*;
|
use crate::comments::*;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#![feature(try_trait)]
|
#![feature(try_trait)]
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
#![feature(proc_macro_hygiene)]
|
#![feature(proc_macro_hygiene)]
|
||||||
|
#![feature(box_patterns)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate diesel;
|
extern crate diesel;
|
||||||
|
Loading…
Reference in New Issue
Block a user