Verify http signatures
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
use activitypub::{Activity, Actor, Object, Link};
|
||||
use array_tool::vec::Uniq;
|
||||
use base64;
|
||||
use reqwest::Client;
|
||||
use rocket::{
|
||||
Outcome,
|
||||
http::Status,
|
||||
http::{Status,HeaderMap},
|
||||
response::{Response, Responder},
|
||||
request::{FromRequest, Request}
|
||||
};
|
||||
@@ -105,7 +106,7 @@ pub fn broadcast<S: sign::Signer, A: Activity, T: inbox::WithInbox + Actor>(send
|
||||
for inbox in boxes {
|
||||
// TODO: run it in Sidekiq or something like that
|
||||
let mut headers = request::headers();
|
||||
headers.set(request::digest(signed.to_string()));
|
||||
headers.set(request::Digest::digest(signed.to_string()));
|
||||
let res = Client::new()
|
||||
.post(&inbox[..])
|
||||
.headers(headers.clone())
|
||||
@@ -119,6 +120,59 @@ pub fn broadcast<S: sign::Signer, A: Activity, T: inbox::WithInbox + Actor>(send
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SignatureValidity {
|
||||
Invalid,
|
||||
ValidNoDigest,
|
||||
Valid,
|
||||
Absent,
|
||||
}
|
||||
|
||||
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") {
|
||||
let mut _key_id = None;
|
||||
let mut _algorithm = None;
|
||||
let mut headers = None;
|
||||
let mut signature = None;
|
||||
for part in sig_header.split(',') {
|
||||
match part {
|
||||
part if part.starts_with("keyId=") => _key_id = Some(&part[7..part.len()-1]),
|
||||
part if part.starts_with("algorithm=") => _algorithm = Some(&part[11..part.len()-1]),
|
||||
part if part.starts_with("headers=") => headers = Some(&part[9..part.len()-1]),
|
||||
part if part.starts_with("signature=") => signature = Some(&part[11..part.len()-1]),
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
if signature.is_some() && headers.is_some() {
|
||||
let headers = headers.unwrap().split_whitespace().collect::<Vec<_>>();
|
||||
let signature = signature.unwrap();
|
||||
let h = headers.iter()
|
||||
.map(|header| (header,all_headers.get_one(header)))
|
||||
.map(|(header, value)| format!("{}: {}", header.to_lowercase(), value.unwrap_or("")))
|
||||
.collect::<Vec<_>>().join("\n");
|
||||
if sender.verify(h, base64::decode(signature).unwrap_or(Vec::new())) {
|
||||
if headers.contains(&"digest") {
|
||||
let digest = all_headers.get_one("digest").unwrap_or("");
|
||||
let digest = request::Digest::from_header(digest);
|
||||
if digest.map(|d| d.verify(data)).unwrap_or(false) {
|
||||
SignatureValidity::Valid
|
||||
} else {
|
||||
SignatureValidity::Invalid
|
||||
}
|
||||
} else {
|
||||
SignatureValidity::ValidNoDigest
|
||||
}
|
||||
} else {
|
||||
SignatureValidity::Invalid
|
||||
}
|
||||
} else {
|
||||
SignatureValidity::Invalid
|
||||
}
|
||||
} else {
|
||||
SignatureValidity::Absent
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct Id(String);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user