Include (request-target) and Host header to HTTP Signature

This commit is contained in:
Kitaiti Makoto 2021-01-21 02:45:29 +09:00
parent 76f7b5e7ac
commit bd1caaf5da
2 changed files with 45 additions and 10 deletions

View File

@ -1,6 +1,6 @@
use activitypub::{Activity, Link, Object}; use activitypub::{Activity, Link, Object};
use array_tool::vec::Uniq; use array_tool::vec::Uniq;
use reqwest::r#async::ClientBuilder; use reqwest::{header::HeaderValue, r#async::ClientBuilder, Url};
use rocket::{ use rocket::{
http::Status, http::Status,
request::{FromRequest, Request}, request::{FromRequest, Request},
@ -143,6 +143,20 @@ where
for inbox in boxes { for inbox in boxes {
let body = signed.to_string(); let body = signed.to_string();
let mut headers = request::headers(); let mut headers = request::headers();
let url = Url::parse(&inbox);
if url.is_err() {
warn!("Inbox is invalid URL: {:?}", &inbox);
continue;
}
let url = url.unwrap();
if !url.has_host() {
warn!("Inbox doesn't have host: {:?}", &inbox);
continue;
};
headers.insert(
"Host",
HeaderValue::from_str(&url.host_str().unwrap()).unwrap(),
);
headers.insert("Digest", request::Digest::digest(&body)); headers.insert("Digest", request::Digest::digest(&body));
rt.spawn( rt.spawn(
client client
@ -150,7 +164,7 @@ where
.headers(headers.clone()) .headers(headers.clone())
.header( .header(
"Signature", "Signature",
request::signature(sender, &headers) request::signature(sender, &headers, "post", url.path(), url.query())
.expect("activity_pub::broadcast: request signature error"), .expect("activity_pub::broadcast: request signature error"),
) )
.body(body) .body(body)

View File

@ -112,25 +112,46 @@ pub fn headers() -> HeaderMap {
headers headers
} }
pub fn signature<S: Signer>(signer: &S, headers: &HeaderMap) -> Result<HeaderValue, Error> { type Method<'a> = &'a str;
let signed_string = headers type Path<'a> = &'a str;
type Query<'a> = &'a str;
pub fn signature<S: Signer>(
signer: &S,
headers: &HeaderMap,
method: Method,
path: Path,
query: Option<Query>,
) -> Result<HeaderValue, Error> {
let origin_form = if let Some(query) = query {
format!("{}?{}", path, query)
} else {
path.to_string()
};
let mut headers = headers
.iter() .iter()
.map(|(h, v)| { .map(|(h, v)| {
format!( (
"{}: {}",
h.as_str().to_lowercase(), h.as_str().to_lowercase(),
v.to_str() v.to_str()
.expect("request::signature: invalid header error") .expect("request::signature: invalid header error"),
) )
}) })
.collect::<Vec<(String, &str)>>();
let request_target = format!("{} {}", method.to_lowercase(), origin_form);
headers.push(("(request-target)".to_string(), &request_target));
let signed_string = headers
.iter()
.map(|(h, v)| format!("{}: {}", h, v))
.collect::<Vec<String>>() .collect::<Vec<String>>()
.join("\n"); .join("\n");
let signed_headers = headers let signed_headers = headers
.iter() .iter()
.map(|(h, _)| h.as_str()) .map(|(h, _)| h.as_ref())
.collect::<Vec<&str>>() .collect::<Vec<&str>>()
.join(" ") .join(" ");
.to_lowercase();
let data = signer.sign(&signed_string).map_err(|_| Error())?; let data = signer.sign(&signed_string).map_err(|_| Error())?;
let sign = base64::encode(&data); let sign = base64::encode(&data);