Refactor and verify http signature on personnal inbox
Verify signature on personnal inbox Reduce code duplication Put Headers in plume-models
This commit is contained in:
parent
0a5d435249
commit
62c94ed463
|
@ -128,6 +128,15 @@ pub enum SignatureValidity {
|
||||||
Absent,
|
Absent,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SignatureValidity {
|
||||||
|
pub fn is_secure(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
SignatureValidity::Valid => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn verify_http_headers<S: sign::Signer+::std::fmt::Debug>(sender: &S, all_headers: HeaderMap, data: String) -> SignatureValidity{
|
pub fn verify_http_headers<S: sign::Signer+::std::fmt::Debug>(sender: &S, all_headers: HeaderMap, data: String) -> SignatureValidity{
|
||||||
if let Some(sig_header) = all_headers.get_one("Signature") {
|
if let Some(sig_header) = all_headers.get_one("Signature") {
|
||||||
let mut _key_id = None;
|
let mut _key_id = None;
|
||||||
|
|
|
@ -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<Self, ()> {
|
||||||
|
let mut headers = HeaderMap::new();
|
||||||
|
for header in request.headers().clone().into_iter() {
|
||||||
|
headers.add(header);
|
||||||
|
}
|
||||||
|
Outcome::Success(Headers(headers))
|
||||||
|
}
|
||||||
|
}
|
|
@ -110,6 +110,7 @@ pub mod blogs;
|
||||||
pub mod comments;
|
pub mod comments;
|
||||||
pub mod db_conn;
|
pub mod db_conn;
|
||||||
pub mod follows;
|
pub mod follows;
|
||||||
|
pub mod headers;
|
||||||
pub mod instance;
|
pub mod instance;
|
||||||
pub mod likes;
|
pub mod likes;
|
||||||
pub mod medias;
|
pub mod medias;
|
||||||
|
|
|
@ -1,16 +1,15 @@
|
||||||
use gettextrs::gettext;
|
use gettextrs::gettext;
|
||||||
use rocket::{http::HeaderMap, Outcome,
|
use rocket::{request::LenientForm, response::Redirect};
|
||||||
request::{self, FromRequest, LenientForm, Request},
|
|
||||||
response::Redirect};
|
|
||||||
use rocket_contrib::{Json, Template};
|
use rocket_contrib::{Json, Template};
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use validator::{Validate};
|
use validator::{Validate};
|
||||||
|
|
||||||
use plume_common::activity_pub::{verify_http_headers, SignatureValidity};
|
use plume_common::activity_pub::verify_http_headers;
|
||||||
use plume_models::{
|
use plume_models::{
|
||||||
admin::Admin,
|
admin::Admin,
|
||||||
comments::Comment,
|
comments::Comment,
|
||||||
db_conn::DbConn,
|
db_conn::DbConn,
|
||||||
|
headers::Headers,
|
||||||
posts::Post,
|
posts::Post,
|
||||||
users::User,
|
users::User,
|
||||||
safe_string::SafeString,
|
safe_string::SafeString,
|
||||||
|
@ -191,22 +190,6 @@ fn ban(_admin: Admin, conn: DbConn, id: i32) -> Redirect {
|
||||||
Redirect::to(uri!(admin_users))
|
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<Self, ()> {
|
|
||||||
let mut headers = HeaderMap::new();
|
|
||||||
for header in request.headers().clone().into_iter() {
|
|
||||||
headers.add(header);
|
|
||||||
}
|
|
||||||
Outcome::Success(Headers{headers})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[post("/inbox", data = "<data>")]
|
#[post("/inbox", data = "<data>")]
|
||||||
fn shared_inbox(conn: DbConn, data: String, headers: Headers) -> String {
|
fn shared_inbox(conn: DbConn, data: String, headers: Headers) -> String {
|
||||||
let act: serde_json::Value = serde_json::from_str(&data[..]).unwrap();
|
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()
|
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"));
|
.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) {
|
let sig = verify_http_headers(&User::from_url(&conn, actor_id.to_owned()).unwrap(), headers.0, data).is_secure();
|
||||||
SignatureValidity::Valid => true,
|
|
||||||
_ => {
|
|
||||||
// TODO verify json signature
|
|
||||||
false
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if !sig {
|
if !sig {
|
||||||
|
// TODO check for valid json-ld signature
|
||||||
return "invalid signature".to_owned();
|
return "invalid signature".to_owned();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,13 +16,14 @@ use workerpool::thunk::*;
|
||||||
|
|
||||||
use plume_common::activity_pub::{
|
use plume_common::activity_pub::{
|
||||||
ActivityStream, broadcast, Id, IntoId, ApRequest,
|
ActivityStream, broadcast, Id, IntoId, ApRequest,
|
||||||
inbox::{FromActivity, Notify, Deletable}
|
verify_http_headers, inbox::{FromActivity, Notify, Deletable}
|
||||||
};
|
};
|
||||||
use plume_common::utils;
|
use plume_common::utils;
|
||||||
use plume_models::{
|
use plume_models::{
|
||||||
blogs::Blog,
|
blogs::Blog,
|
||||||
db_conn::DbConn,
|
db_conn::DbConn,
|
||||||
follows,
|
follows,
|
||||||
|
headers::Headers,
|
||||||
instance::Instance,
|
instance::Instance,
|
||||||
posts::Post,
|
posts::Post,
|
||||||
reshares::Reshare,
|
reshares::Reshare,
|
||||||
|
@ -295,13 +296,20 @@ fn outbox(name: String, conn: DbConn) -> ActivityStream<OrderedCollection> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/@/<name>/inbox", data = "<data>")]
|
#[post("/@/<name>/inbox", data = "<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 user = User::find_local(&*conn, name).unwrap();
|
||||||
let act: serde_json::Value = serde_json::from_str(&data[..]).unwrap();
|
let act: serde_json::Value = serde_json::from_str(&data[..]).unwrap();
|
||||||
|
|
||||||
let activity = act.clone();
|
let activity = act.clone();
|
||||||
let actor_id = activity["actor"].as_str()
|
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"));
|
.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()) {
|
if Instance::is_blocked(&*conn, actor_id.to_string()) {
|
||||||
return String::new();
|
return String::new();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue