diff --git a/plume-common/src/activity_pub/mod.rs b/plume-common/src/activity_pub/mod.rs index bf83530b..dd739634 100644 --- a/plume-common/src/activity_pub/mod.rs +++ b/plume-common/src/activity_pub/mod.rs @@ -1,6 +1,6 @@ use activitypub::{Activity, Link, Object}; use array_tool::vec::Uniq; -use reqwest::r#async::ClientBuilder; +use reqwest::{header::HeaderValue, r#async::ClientBuilder, Url}; use rocket::{ http::Status, request::{FromRequest, Request}, @@ -143,6 +143,20 @@ where for inbox in boxes { let body = signed.to_string(); 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)); rt.spawn( client @@ -150,7 +164,7 @@ where .headers(headers.clone()) .header( "Signature", - request::signature(sender, &headers) + request::signature(sender, &headers, "post", url.path(), url.query()) .expect("activity_pub::broadcast: request signature error"), ) .body(body) diff --git a/plume-common/src/activity_pub/request.rs b/plume-common/src/activity_pub/request.rs index 35bc0059..4ffe7754 100644 --- a/plume-common/src/activity_pub/request.rs +++ b/plume-common/src/activity_pub/request.rs @@ -112,25 +112,46 @@ pub fn headers() -> HeaderMap { headers } -pub fn signature(signer: &S, headers: &HeaderMap) -> Result { - let signed_string = headers +type Method<'a> = &'a str; +type Path<'a> = &'a str; +type Query<'a> = &'a str; + +pub fn signature( + signer: &S, + headers: &HeaderMap, + method: Method, + path: Path, + query: Option, +) -> Result { + let origin_form = if let Some(query) = query { + format!("{}?{}", path, query) + } else { + path.to_string() + }; + + let mut headers = headers .iter() .map(|(h, v)| { - format!( - "{}: {}", + ( h.as_str().to_lowercase(), v.to_str() - .expect("request::signature: invalid header error") + .expect("request::signature: invalid header error"), ) }) + .collect::>(); + 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::>() .join("\n"); let signed_headers = headers .iter() - .map(|(h, _)| h.as_str()) + .map(|(h, _)| h.as_ref()) .collect::>() - .join(" ") - .to_lowercase(); + .join(" "); let data = signer.sign(&signed_string).map_err(|_| Error())?; let sign = base64::encode(&data);