mirror of
https://gitlab.computer.surgery/matrix/grapevine.git
synced 2025-12-18 16:21: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::{
|
use ruma::{
|
||||||
api::{
|
api::{
|
||||||
client::error::Error as RumaError, EndpointError, IncomingResponse,
|
client::error::Error as RumaError, EndpointError, IncomingResponse,
|
||||||
MatrixVersion, OutgoingRequest, SendAccessToken,
|
MatrixVersion, Metadata, OutgoingRequest, SendAccessToken,
|
||||||
},
|
},
|
||||||
serde::Base64,
|
serde::Base64,
|
||||||
server_util::authorization::XMatrix,
|
server_util::authorization::XMatrix,
|
||||||
OwnedServerName, OwnedSigningKeyId, ServerName,
|
OwnedServerName, OwnedSigningKeyId, ServerName,
|
||||||
};
|
};
|
||||||
use tracing::{debug, field, warn};
|
use thiserror::Error;
|
||||||
|
use tracing::{debug, error, field, warn};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
observability::{FoundIn, Lookup, METRICS},
|
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))]
|
#[tracing::instrument(skip(request, log_error), fields(url))]
|
||||||
pub(crate) async fn send_request<T>(
|
pub(crate) async fn send_request<T>(
|
||||||
destination: &ServerName,
|
destination: &ServerName,
|
||||||
|
|
@ -138,67 +215,13 @@ where
|
||||||
Error::BadServerResponse("Invalid request")
|
Error::BadServerResponse("Invalid request")
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let mut request_map = serde_json::Map::new();
|
let signature = create_request_signature(
|
||||||
|
&http_request,
|
||||||
if !http_request.body().is_empty() {
|
&T::METADATA,
|
||||||
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(),
|
|
||||||
destination.to_owned(),
|
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)?;
|
let reqwest_request = reqwest::Request::try_from(http_request)?;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue