From 62c94ed463dd01f9df5c1fdb0eea9f991acb3996 Mon Sep 17 00:00:00 2001 From: Trinity Pointard Date: Wed, 3 Oct 2018 20:48:25 +0200 Subject: [PATCH] Refactor and verify http signature on personnal inbox Verify signature on personnal inbox Reduce code duplication Put Headers in plume-models --- plume-common/src/activity_pub/mod.rs | 9 ++++++++ plume-models/src/headers.rs | 17 +++++++++++++++ plume-models/src/lib.rs | 1 + src/routes/instance.rs | 32 +++++----------------------- src/routes/user.rs | 12 +++++++++-- 5 files changed, 42 insertions(+), 29 deletions(-) create mode 100644 plume-models/src/headers.rs diff --git a/plume-common/src/activity_pub/mod.rs b/plume-common/src/activity_pub/mod.rs index 9b614f13..c0ad233a 100644 --- a/plume-common/src/activity_pub/mod.rs +++ b/plume-common/src/activity_pub/mod.rs @@ -128,6 +128,15 @@ pub enum SignatureValidity { Absent, } +impl SignatureValidity { + pub fn is_secure(&self) -> bool { + match self { + SignatureValidity::Valid => true, + _ => false, + } + } +} + pub fn verify_http_headers(sender: &S, all_headers: HeaderMap, data: String) -> SignatureValidity{ if let Some(sig_header) = all_headers.get_one("Signature") { let mut _key_id = None; diff --git a/plume-models/src/headers.rs b/plume-models/src/headers.rs new file mode 100644 index 00000000..d94b86a5 --- /dev/null +++ b/plume-models/src/headers.rs @@ -0,0 +1,17 @@ +use rocket::request::{self, FromRequest, Request}; +use rocket::{http::HeaderMap, Outcome}; + + +pub struct Headers<'r>(pub HeaderMap<'r>); + +impl<'a, 'r> FromRequest<'a, 'r> for Headers<'r> { + type Error = (); + + fn from_request(request: &'a Request<'r>) -> request::Outcome { + let mut headers = HeaderMap::new(); + for header in request.headers().clone().into_iter() { + headers.add(header); + } + Outcome::Success(Headers(headers)) + } +} diff --git a/plume-models/src/lib.rs b/plume-models/src/lib.rs index 71c4f4e5..0afdd738 100644 --- a/plume-models/src/lib.rs +++ b/plume-models/src/lib.rs @@ -110,6 +110,7 @@ pub mod blogs; pub mod comments; pub mod db_conn; pub mod follows; +pub mod headers; pub mod instance; pub mod likes; pub mod medias; diff --git a/src/routes/instance.rs b/src/routes/instance.rs index 16672caf..8f592ed9 100644 --- a/src/routes/instance.rs +++ b/src/routes/instance.rs @@ -1,16 +1,15 @@ use gettextrs::gettext; -use rocket::{http::HeaderMap, Outcome, - request::{self, FromRequest, LenientForm, Request}, - response::Redirect}; +use rocket::{request::LenientForm, response::Redirect}; use rocket_contrib::{Json, Template}; use serde_json; use validator::{Validate}; -use plume_common::activity_pub::{verify_http_headers, SignatureValidity}; +use plume_common::activity_pub::verify_http_headers; use plume_models::{ admin::Admin, comments::Comment, db_conn::DbConn, + headers::Headers, posts::Post, users::User, safe_string::SafeString, @@ -191,22 +190,6 @@ fn ban(_admin: Admin, conn: DbConn, id: i32) -> Redirect { Redirect::to(uri!(admin_users)) } -struct Headers<'r> { - headers: HeaderMap<'r>, -} - -impl<'a, 'r> FromRequest<'a, 'r> for Headers<'r> { - type Error = (); - - fn from_request(request: &'a Request<'r>) ->request::Outcome { - let mut headers = HeaderMap::new(); - for header in request.headers().clone().into_iter() { - headers.add(header); - } - Outcome::Success(Headers{headers}) - } -} - #[post("/inbox", data = "")] fn shared_inbox(conn: DbConn, data: String, headers: Headers) -> String { let act: serde_json::Value = serde_json::from_str(&data[..]).unwrap(); @@ -215,14 +198,9 @@ fn shared_inbox(conn: DbConn, data: String, headers: Headers) -> String { let actor_id = activity["actor"].as_str() .unwrap_or_else(|| activity["actor"]["id"].as_str().expect("No actor ID for incoming activity, blocks by panicking")); - let sig = match verify_http_headers(&User::from_url(&conn, actor_id.to_owned()).unwrap(), headers.headers, data) { - SignatureValidity::Valid => true, - _ => { - // TODO verify json signature - false - } - }; + let sig = verify_http_headers(&User::from_url(&conn, actor_id.to_owned()).unwrap(), headers.0, data).is_secure(); if !sig { + // TODO check for valid json-ld signature return "invalid signature".to_owned(); } diff --git a/src/routes/user.rs b/src/routes/user.rs index 42ac6230..c206e51b 100644 --- a/src/routes/user.rs +++ b/src/routes/user.rs @@ -16,13 +16,14 @@ use workerpool::thunk::*; use plume_common::activity_pub::{ ActivityStream, broadcast, Id, IntoId, ApRequest, - inbox::{FromActivity, Notify, Deletable} + verify_http_headers, inbox::{FromActivity, Notify, Deletable} }; use plume_common::utils; use plume_models::{ blogs::Blog, db_conn::DbConn, follows, + headers::Headers, instance::Instance, posts::Post, reshares::Reshare, @@ -295,13 +296,20 @@ fn outbox(name: String, conn: DbConn) -> ActivityStream { } #[post("/@//inbox", data = "")] -fn inbox(name: String, conn: DbConn, data: String) -> String { +fn inbox(name: String, conn: DbConn, data: String, headers: Headers) -> String { let user = User::find_local(&*conn, name).unwrap(); let act: serde_json::Value = serde_json::from_str(&data[..]).unwrap(); let activity = act.clone(); let actor_id = activity["actor"].as_str() .unwrap_or_else(|| activity["actor"]["id"].as_str().expect("User: No actor ID for incoming activity, blocks by panicking")); + + let sig = verify_http_headers(&User::from_url(&conn, actor_id.to_owned()).unwrap(), headers.0, data).is_secure(); + if !sig { + // TODO check for json-ld signature + return "invalid signature".to_owned(); + } + if Instance::is_blocked(&*conn, actor_id.to_string()) { return String::new(); }