mirror of
https://gitlab.computer.surgery/matrix/grapevine.git
synced 2025-12-18 00:01:24 +01:00
send_request: factor out signature creation
This commit is contained in:
parent
f37e52c99e
commit
7a7a839862
1 changed files with 85 additions and 62 deletions
|
|
@ -8,13 +8,14 @@ use axum_extra::headers::{Authorization, HeaderMapExt};
|
|||
use ruma::{
|
||||
api::{
|
||||
client::error::Error as RumaError, EndpointError, IncomingResponse,
|
||||
MatrixVersion, OutgoingRequest, SendAccessToken,
|
||||
MatrixVersion, Metadata, OutgoingRequest, SendAccessToken,
|
||||
},
|
||||
serde::Base64,
|
||||
server_util::authorization::XMatrix,
|
||||
OwnedServerName, OwnedSigningKeyId, ServerName,
|
||||
};
|
||||
use tracing::{debug, field, warn};
|
||||
use thiserror::Error;
|
||||
use tracing::{debug, error, field, warn};
|
||||
|
||||
use crate::{
|
||||
observability::{FoundIn, Lookup, METRICS},
|
||||
|
|
@ -79,6 +80,82 @@ impl FedDest {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
enum RequestSignError {
|
||||
#[error("invalid JSON in request body")]
|
||||
InvalidBodyJson(#[source] serde_json::Error),
|
||||
#[error("request has no path")]
|
||||
NoPath,
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(http_request, metadata))]
|
||||
fn create_request_signature(
|
||||
http_request: &http::Request<Vec<u8>>,
|
||||
metadata: &Metadata,
|
||||
destination: OwnedServerName,
|
||||
) -> Result<Authorization<XMatrix>, RequestSignError> {
|
||||
let mut request_map = serde_json::Map::new();
|
||||
|
||||
if !http_request.body().is_empty() {
|
||||
request_map.insert(
|
||||
"content".to_owned(),
|
||||
serde_json::from_slice(http_request.body())
|
||||
.map_err(RequestSignError::InvalidBodyJson)?,
|
||||
);
|
||||
};
|
||||
|
||||
request_map.insert("method".to_owned(), metadata.method.to_string().into());
|
||||
request_map.insert(
|
||||
"uri".to_owned(),
|
||||
http_request
|
||||
.uri()
|
||||
.path_and_query()
|
||||
.ok_or(RequestSignError::NoPath)?
|
||||
.to_string()
|
||||
.into(),
|
||||
);
|
||||
request_map.insert(
|
||||
"origin".to_owned(),
|
||||
services().globals.server_name().as_str().into(),
|
||||
);
|
||||
request_map.insert("destination".to_owned(), destination.as_str().into());
|
||||
|
||||
let mut request_json = serde_json::from_value(request_map.into())
|
||||
.expect("valid JSON is valid BTreeMap");
|
||||
|
||||
ruma::signatures::sign_json(
|
||||
services().globals.server_name().as_str(),
|
||||
services().globals.keypair(),
|
||||
&mut request_json,
|
||||
)
|
||||
.expect("our request json is what ruma expects");
|
||||
|
||||
let request_json: serde_json::Map<String, serde_json::Value> =
|
||||
serde_json::from_slice(&serde_json::to_vec(&request_json).unwrap())
|
||||
.unwrap();
|
||||
|
||||
// There's exactly the one signature we just created, fish it back out again
|
||||
let (key_id, signature) = request_json["signatures"]
|
||||
.get(services().globals.server_name().as_str())
|
||||
.unwrap()
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.next()
|
||||
.unwrap();
|
||||
|
||||
let key_id = OwnedSigningKeyId::try_from(key_id.clone()).unwrap();
|
||||
let signature = Base64::parse(signature.as_str().unwrap())
|
||||
.expect("generated signature should be valid base64");
|
||||
|
||||
Ok(Authorization(XMatrix::new(
|
||||
services().globals.server_name().to_owned(),
|
||||
destination,
|
||||
key_id,
|
||||
signature,
|
||||
)))
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(request, log_error), fields(url))]
|
||||
pub(crate) async fn send_request<T>(
|
||||
destination: &ServerName,
|
||||
|
|
@ -138,67 +215,13 @@ where
|
|||
Error::BadServerResponse("Invalid request")
|
||||
})?;
|
||||
|
||||
let mut request_map = serde_json::Map::new();
|
||||
|
||||
if !http_request.body().is_empty() {
|
||||
request_map.insert(
|
||||
"content".to_owned(),
|
||||
serde_json::from_slice(http_request.body())
|
||||
.expect("body is valid json, we just created it"),
|
||||
);
|
||||
};
|
||||
|
||||
request_map
|
||||
.insert("method".to_owned(), T::METADATA.method.to_string().into());
|
||||
request_map.insert(
|
||||
"uri".to_owned(),
|
||||
http_request
|
||||
.uri()
|
||||
.path_and_query()
|
||||
.expect("all requests have a path")
|
||||
.to_string()
|
||||
.into(),
|
||||
);
|
||||
request_map.insert(
|
||||
"origin".to_owned(),
|
||||
services().globals.server_name().as_str().into(),
|
||||
);
|
||||
request_map.insert("destination".to_owned(), destination.as_str().into());
|
||||
|
||||
let mut request_json = serde_json::from_value(request_map.into())
|
||||
.expect("valid JSON is valid BTreeMap");
|
||||
|
||||
ruma::signatures::sign_json(
|
||||
services().globals.server_name().as_str(),
|
||||
services().globals.keypair(),
|
||||
&mut request_json,
|
||||
)
|
||||
.expect("our request json is what ruma expects");
|
||||
|
||||
let request_json: serde_json::Map<String, serde_json::Value> =
|
||||
serde_json::from_slice(&serde_json::to_vec(&request_json).unwrap())
|
||||
.unwrap();
|
||||
|
||||
// There's exactly the one signature we just created, fish it back out again
|
||||
let (key_id, signature) = request_json["signatures"]
|
||||
.get(services().globals.server_name().as_str())
|
||||
.unwrap()
|
||||
.as_object()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.next()
|
||||
.unwrap();
|
||||
|
||||
let key_id = OwnedSigningKeyId::try_from(key_id.clone()).unwrap();
|
||||
let signature = Base64::parse(signature.as_str().unwrap())
|
||||
.expect("generated signature should be valid base64");
|
||||
|
||||
http_request.headers_mut().typed_insert(Authorization(XMatrix::new(
|
||||
services().globals.server_name().to_owned(),
|
||||
let signature = create_request_signature(
|
||||
&http_request,
|
||||
&T::METADATA,
|
||||
destination.to_owned(),
|
||||
key_id,
|
||||
signature,
|
||||
)));
|
||||
)
|
||||
.expect("all outgoing requests can be signed");
|
||||
http_request.headers_mut().typed_insert(signature);
|
||||
|
||||
let reqwest_request = reqwest::Request::try_from(http_request)?;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue