entelix_cloud/bedrock/
signer.rs1use aws_credential_types::Credentials;
13use aws_sigv4::http_request::{SignableBody, SignableRequest, SigningSettings, sign};
14use aws_sigv4::sign::v4;
15
16use crate::CloudError;
17
18const SERVICE_NAME: &str = "bedrock";
19
20#[derive(Clone, Debug)]
22pub struct BedrockSigner {
23 region: String,
24}
25
26impl BedrockSigner {
27 pub fn new(region: impl Into<String>) -> Self {
30 Self {
31 region: region.into(),
32 }
33 }
34
35 pub fn region(&self) -> &str {
37 &self.region
38 }
39
40 pub fn sign_request(
44 &self,
45 creds: &Credentials,
46 method: &str,
47 url: &str,
48 headers: &[(String, String)],
49 body: &[u8],
50 ) -> Result<Vec<(String, String)>, CloudError> {
51 let identity = creds.clone().into();
52 let signing_settings = SigningSettings::default();
53 let signing_params = v4::SigningParams::builder()
54 .identity(&identity)
55 .region(&self.region)
56 .name(SERVICE_NAME)
57 .time(std::time::SystemTime::now())
58 .settings(signing_settings)
59 .build()
60 .map_err(|e| CloudError::Signing {
61 message: format!("build signing params: {e}"),
62 source: Some(Box::new(e)),
63 })?
64 .into();
65
66 let header_pairs: Vec<(&str, &str)> = headers
67 .iter()
68 .map(|(n, v)| (n.as_str(), v.as_str()))
69 .collect();
70 let signable = SignableRequest::new(
71 method,
72 url,
73 header_pairs.into_iter(),
74 SignableBody::Bytes(body),
75 )
76 .map_err(|e| CloudError::Signing {
77 message: format!("build signable request: {e}"),
78 source: Some(Box::new(e)),
79 })?;
80
81 let (instructions, _signature) = sign(signable, &signing_params)
82 .map_err(|e| CloudError::Signing {
83 message: format!("sign: {e}"),
84 source: Some(Box::new(e)),
85 })?
86 .into_parts();
87
88 let mut out = Vec::new();
89 let (sigv4_headers, _) = instructions.into_parts();
90 for header in sigv4_headers {
91 out.push((header.name().to_owned(), header.value().to_owned()));
92 }
93 Ok(out)
94 }
95}