1use crate::error::{HyperSigError, HyperSigResult};
2use http::{HeaderMap, Request, Response};
3use http_body::Body;
4use httpsig::prelude::{
5 message_component::{
6 DerivedComponentName, HttpMessageComponent, HttpMessageComponentId, HttpMessageComponentName, HttpMessageComponentParam,
7 },
8 AlgorithmName, HttpSignatureBase, HttpSignatureHeaders, HttpSignatureHeadersMap, HttpSignatureParams, SigningKey, VerifyingKey,
9};
10use indexmap::{IndexMap, IndexSet};
11use std::{future::Future, str::FromStr};
12
13type SignatureName = String;
15type KeyId = String;
17
18pub trait MessageSignature {
21 type Error;
22
23 fn has_message_signature(&self) -> bool;
25
26 fn get_alg_key_ids(&self) -> Result<IndexMap<SignatureName, (Option<AlgorithmName>, Option<KeyId>)>, Self::Error>;
28
29 fn get_signature_params(&self) -> Result<IndexMap<SignatureName, HttpSignatureParams>, Self::Error>;
31}
32
33pub trait MessageSignatureReq {
35 type Error;
36 fn set_message_signature<T>(
38 &mut self,
39 signature_params: &HttpSignatureParams,
40 signing_key: &T,
41 signature_name: Option<&str>,
42 ) -> impl Future<Output = Result<(), Self::Error>> + Send
43 where
44 Self: Sized,
45 T: SigningKey + Sync;
46
47 fn set_message_signatures<T>(
49 &mut self,
50 params_key_name: &[(&HttpSignatureParams, &T, Option<&str>)],
51 ) -> impl Future<Output = Result<(), Self::Error>> + Send
52 where
53 Self: Sized,
54 T: SigningKey + Sync;
55
56 fn verify_message_signature<T>(
58 &self,
59 verifying_key: &T,
60 key_id: Option<&str>,
61 ) -> impl Future<Output = Result<SignatureName, Self::Error>> + Send
62 where
63 Self: Sized,
64 T: VerifyingKey + Sync;
65
66 fn verify_message_signatures<T>(
68 &self,
69 key_and_id: &[(&T, Option<&str>)],
70 ) -> impl Future<Output = Result<Vec<Result<SignatureName, Self::Error>>, Self::Error>> + Send
71 where
72 Self: Sized,
73 T: VerifyingKey + Sync;
74
75 fn extract_signatures(&self) -> Result<IndexMap<SignatureName, (HttpSignatureBase, HttpSignatureHeaders)>, Self::Error>;
77}
78
79pub trait MessageSignatureRes {
81 type Error;
82 fn set_message_signature<T, B>(
84 &mut self,
85 signature_params: &HttpSignatureParams,
86 signing_key: &T,
87 signature_name: Option<&str>,
88 req_for_param: Option<&Request<B>>,
89 ) -> impl Future<Output = Result<(), Self::Error>> + Send
90 where
91 Self: Sized,
92 T: SigningKey + Sync,
93 B: Sync;
94
95 fn set_message_signatures<T, B>(
97 &mut self,
98 params_key_name: &[(&HttpSignatureParams, &T, Option<&str>)],
99 req_for_param: Option<&Request<B>>,
100 ) -> impl Future<Output = Result<(), Self::Error>> + Send
101 where
102 Self: Sized,
103 T: SigningKey + Sync,
104 B: Sync;
105
106 fn verify_message_signature<T, B>(
108 &self,
109 verifying_key: &T,
110 key_id: Option<&str>,
111 req_for_param: Option<&Request<B>>,
112 ) -> impl Future<Output = Result<SignatureName, Self::Error>> + Send
113 where
114 Self: Sized,
115 T: VerifyingKey + Sync,
116 B: Sync;
117
118 fn verify_message_signatures<T, B>(
120 &self,
121 key_and_id: &[(&T, Option<&str>)],
122 req_for_param: Option<&Request<B>>,
123 ) -> impl Future<Output = Result<Vec<Result<SignatureName, Self::Error>>, Self::Error>> + Send
124 where
125 Self: Sized,
126 T: VerifyingKey + Sync,
127 B: Sync;
128
129 fn extract_signatures<B>(
131 &self,
132 req_for_param: Option<&Request<B>>,
133 ) -> Result<IndexMap<SignatureName, (HttpSignatureBase, HttpSignatureHeaders)>, Self::Error>;
134}
135
136#[cfg(feature = "blocking")]
138pub trait MessageSignatureReqSync: MessageSignatureReq {
147 fn set_message_signature_sync<T>(
148 &mut self,
149 signature_params: &HttpSignatureParams,
150 signing_key: &T,
151 signature_name: Option<&str>,
152 ) -> Result<(), Self::Error>
153 where
154 Self: Sized,
155 T: SigningKey + Sync;
156
157 fn set_message_signatures_sync<T>(
158 &mut self,
159 params_key_name: &[(&HttpSignatureParams, &T, Option<&str>)],
160 ) -> Result<(), Self::Error>
161 where
162 Self: Sized,
163 T: SigningKey + Sync;
164
165 fn verify_message_signature_sync<T>(&self, verifying_key: &T, key_id: Option<&str>) -> Result<SignatureName, Self::Error>
166 where
167 Self: Sized,
168 T: VerifyingKey + Sync;
169
170 fn verify_message_signatures_sync<T>(
171 &self,
172 key_and_id: &[(&T, Option<&str>)],
173 ) -> Result<Vec<Result<SignatureName, Self::Error>>, Self::Error>
174 where
175 Self: Sized,
176 T: VerifyingKey + Sync;
177}
178
179#[cfg(feature = "blocking")]
180pub trait MessageSignatureResSync: MessageSignatureRes {
189 fn set_message_signature_sync<T, B>(
190 &mut self,
191 signature_params: &HttpSignatureParams,
192 signing_key: &T,
193 signature_name: Option<&str>,
194 req_for_param: Option<&Request<B>>,
195 ) -> Result<(), Self::Error>
196 where
197 Self: Sized,
198 T: SigningKey + Sync,
199 B: Sync;
200
201 fn set_message_signatures_sync<T, B>(
202 &mut self,
203 params_key_name: &[(&HttpSignatureParams, &T, Option<&str>)],
204 req_for_param: Option<&Request<B>>,
205 ) -> Result<(), Self::Error>
206 where
207 Self: Sized,
208 T: SigningKey + Sync,
209 B: Sync;
210
211 fn verify_message_signature_sync<T, B>(
212 &self,
213 verifying_key: &T,
214 key_id: Option<&str>,
215 req_for_param: Option<&Request<B>>,
216 ) -> Result<SignatureName, Self::Error>
217 where
218 Self: Sized,
219 T: VerifyingKey + Sync,
220 B: Sync;
221
222 fn verify_message_signatures_sync<T, B>(
223 &self,
224 key_and_id: &[(&T, Option<&str>)],
225 req_for_param: Option<&Request<B>>,
226 ) -> Result<Vec<Result<SignatureName, Self::Error>>, Self::Error>
227 where
228 Self: Sized,
229 T: VerifyingKey + Sync,
230 B: Sync;
231}
232
233impl<D> MessageSignature for Request<D>
235where
236 D: Send + Body + Sync,
237{
238 type Error = HyperSigError;
239
240 fn has_message_signature(&self) -> bool {
242 has_message_signature_inner(self.headers())
243 }
244
245 fn get_alg_key_ids(&self) -> HyperSigResult<IndexMap<SignatureName, (Option<AlgorithmName>, Option<KeyId>)>> {
247 let req_or_res = RequestOrResponse::Request(self);
248 get_alg_key_ids_inner(&req_or_res)
249 }
250
251 fn get_signature_params(&self) -> Result<IndexMap<SignatureName, HttpSignatureParams>, Self::Error> {
253 let req_or_res = RequestOrResponse::Request(self);
254 get_signature_params_inner(&req_or_res)
255 }
256}
257
258impl<D> MessageSignatureReq for Request<D>
259where
260 D: Send + Body + Sync,
261{
262 type Error = HyperSigError;
263
264 async fn set_message_signature<T>(
266 &mut self,
267 signature_params: &HttpSignatureParams,
268 signing_key: &T,
269 signature_name: Option<&str>,
270 ) -> HyperSigResult<()>
271 where
272 Self: Sized,
273 T: SigningKey + Sync,
274 {
275 self
276 .set_message_signatures(&[(signature_params, signing_key, signature_name)])
277 .await
278 }
279
280 async fn set_message_signatures<T>(
281 &mut self,
282 params_key_name: &[(&HttpSignatureParams, &T, Option<&str>)],
283 ) -> Result<(), Self::Error>
284 where
285 Self: Sized,
286 T: SigningKey + Sync,
287 {
288 let req_or_res = RequestOrResponse::Request(self);
289 let vec_signature_bases = params_key_name
290 .iter()
291 .map(|(params, key, name)| {
292 build_signature_base(&req_or_res, params, None as Option<&Request<()>>).map(|base| (base, *key, *name))
293 })
294 .collect::<Result<Vec<_>, _>>()?;
295 let vec_signature_headers = futures::future::join_all(
296 vec_signature_bases
297 .into_iter()
298 .map(|(base, key, name)| async move { base.build_signature_headers(key, name) }),
299 )
300 .await
301 .into_iter()
302 .collect::<Result<Vec<_>, _>>()?;
303 vec_signature_headers.iter().try_for_each(|headers| {
304 self
305 .headers_mut()
306 .append("signature-input", headers.signature_input_header_value().parse()?);
307 self
308 .headers_mut()
309 .append("signature", headers.signature_header_value().parse()?);
310 Ok(()) as Result<(), HyperSigError>
311 })
312 }
313
314 async fn verify_message_signature<T>(&self, verifying_key: &T, key_id: Option<&str>) -> HyperSigResult<SignatureName>
319 where
320 Self: Sized,
321 T: VerifyingKey + Sync,
322 {
323 self
324 .verify_message_signatures(&[(verifying_key, key_id)])
325 .await?
326 .pop()
327 .unwrap()
328 }
329
330 async fn verify_message_signatures<T>(
331 &self,
332 key_and_id: &[(&T, Option<&str>)],
333 ) -> Result<Vec<Result<SignatureName, Self::Error>>, Self::Error>
334 where
335 Self: Sized,
336 T: VerifyingKey + Sync,
337 {
338 if !self.has_message_signature() {
339 return Err(HyperSigError::NoSignatureHeaders(
340 "The request does not have signature and signature-input headers".to_string(),
341 ));
342 }
343 let map_signature_with_base = self.extract_signatures()?;
344 verify_message_signatures_inner(&map_signature_with_base, key_and_id).await
345 }
346
347 fn extract_signatures(&self) -> Result<IndexMap<SignatureName, (HttpSignatureBase, HttpSignatureHeaders)>, Self::Error> {
349 let req_or_res = RequestOrResponse::Request(self);
350 extract_signatures_inner(&req_or_res, None as Option<&Request<()>>)
351 }
352}
353
354impl<D> MessageSignature for Response<D>
356where
357 D: Send + Body + Sync,
358{
359 type Error = HyperSigError;
360
361 fn has_message_signature(&self) -> bool {
363 has_message_signature_inner(self.headers())
364 }
365
366 fn get_alg_key_ids(&self) -> Result<IndexMap<SignatureName, (Option<AlgorithmName>, Option<KeyId>)>, Self::Error> {
368 let req_or_res = RequestOrResponse::Response(self);
369 get_alg_key_ids_inner(&req_or_res)
370 }
371
372 fn get_signature_params(&self) -> Result<IndexMap<SignatureName, HttpSignatureParams>, Self::Error> {
374 let req_or_res = RequestOrResponse::Response(self);
375 get_signature_params_inner(&req_or_res)
376 }
377}
378
379impl<D> MessageSignatureRes for Response<D>
380where
381 D: Send + Body + Sync,
382{
383 type Error = HyperSigError;
384
385 async fn set_message_signature<T, B>(
387 &mut self,
388 signature_params: &HttpSignatureParams,
389 signing_key: &T,
390 signature_name: Option<&str>,
391 req_for_param: Option<&Request<B>>,
392 ) -> Result<(), Self::Error>
393 where
394 Self: Sized,
395 T: SigningKey + Sync,
396 B: Sync,
397 {
398 self
399 .set_message_signatures(&[(signature_params, signing_key, signature_name)], req_for_param)
400 .await
401 }
402
403 async fn set_message_signatures<T, B>(
404 &mut self,
405 params_key_name: &[(&HttpSignatureParams, &T, Option<&str>)],
406 req_for_param: Option<&Request<B>>,
407 ) -> Result<(), Self::Error>
408 where
409 Self: Sized,
410 T: SigningKey + Sync,
411 {
412 let req_or_res = RequestOrResponse::Response(self);
413
414 let vec_signature_bases = params_key_name
415 .iter()
416 .map(|(params, key, name)| build_signature_base(&req_or_res, params, req_for_param).map(|base| (base, *key, *name)))
417 .collect::<Result<Vec<_>, _>>()?;
418 let vec_signature_headers = futures::future::join_all(
419 vec_signature_bases
420 .into_iter()
421 .map(|(base, key, name)| async move { base.build_signature_headers(key, name) }),
422 )
423 .await
424 .into_iter()
425 .collect::<Result<Vec<_>, _>>()?;
426
427 vec_signature_headers.iter().try_for_each(|headers| {
428 self
429 .headers_mut()
430 .append("signature-input", headers.signature_input_header_value().parse()?);
431 self
432 .headers_mut()
433 .append("signature", headers.signature_header_value().parse()?);
434 Ok(()) as Result<(), HyperSigError>
435 })
436 }
437
438 async fn verify_message_signature<T, B>(
443 &self,
444 verifying_key: &T,
445 key_id: Option<&str>,
446 req_for_param: Option<&Request<B>>,
447 ) -> Result<SignatureName, Self::Error>
448 where
449 Self: Sized,
450 T: VerifyingKey + Sync,
451 B: Sync,
452 {
453 self
454 .verify_message_signatures(&[(verifying_key, key_id)], req_for_param)
455 .await?
456 .pop()
457 .unwrap()
458 }
459
460 async fn verify_message_signatures<T, B>(
461 &self,
462 key_and_id: &[(&T, Option<&str>)],
463 req_for_param: Option<&Request<B>>,
464 ) -> Result<Vec<Result<SignatureName, Self::Error>>, Self::Error>
465 where
466 Self: Sized,
467 T: VerifyingKey + Sync,
468 {
469 if !self.has_message_signature() {
470 return Err(HyperSigError::NoSignatureHeaders(
471 "The response does not have signature and signature-input headers".to_string(),
472 ));
473 }
474 let map_signature_with_base = self.extract_signatures(req_for_param)?;
475 verify_message_signatures_inner(&map_signature_with_base, key_and_id).await
476 }
477
478 fn extract_signatures<B>(
480 &self,
481 req_for_param: Option<&Request<B>>,
482 ) -> Result<IndexMap<SignatureName, (HttpSignatureBase, HttpSignatureHeaders)>, Self::Error> {
483 let req_or_res = RequestOrResponse::Response(self);
484 extract_signatures_inner(&req_or_res, req_for_param)
485 }
486}
487
488#[cfg(feature = "blocking")]
490impl<D> MessageSignatureReqSync for Request<D>
491where
492 D: Send + Body + Sync,
493{
494 fn set_message_signature_sync<T>(
495 &mut self,
496 signature_params: &HttpSignatureParams,
497 signing_key: &T,
498 signature_name: Option<&str>,
499 ) -> Result<(), Self::Error>
500 where
501 Self: Sized,
502 T: SigningKey + Sync,
503 {
504 futures::executor::block_on(self.set_message_signature(signature_params, signing_key, signature_name))
505 }
506
507 fn set_message_signatures_sync<T>(
508 &mut self,
509 params_key_name: &[(&HttpSignatureParams, &T, Option<&str>)],
510 ) -> Result<(), Self::Error>
511 where
512 Self: Sized,
513 T: SigningKey + Sync,
514 {
515 futures::executor::block_on(self.set_message_signatures(params_key_name))
516 }
517
518 fn verify_message_signature_sync<T>(&self, verifying_key: &T, key_id: Option<&str>) -> Result<SignatureName, Self::Error>
519 where
520 Self: Sized,
521 T: VerifyingKey + Sync,
522 {
523 futures::executor::block_on(self.verify_message_signature(verifying_key, key_id))
524 }
525
526 fn verify_message_signatures_sync<T>(
527 &self,
528 key_and_id: &[(&T, Option<&str>)],
529 ) -> Result<Vec<Result<SignatureName, Self::Error>>, Self::Error>
530 where
531 Self: Sized,
532 T: VerifyingKey + Sync,
533 {
534 futures::executor::block_on(self.verify_message_signatures(key_and_id))
535 }
536}
537
538#[cfg(feature = "blocking")]
539impl<D> MessageSignatureResSync for Response<D>
540where
541 D: Send + Body + Sync,
542{
543 fn set_message_signature_sync<T, B>(
544 &mut self,
545 signature_params: &HttpSignatureParams,
546 signing_key: &T,
547 signature_name: Option<&str>,
548 req_for_param: Option<&Request<B>>,
549 ) -> Result<(), Self::Error>
550 where
551 Self: Sized,
552 T: SigningKey + Sync,
553 B: Sync,
554 {
555 futures::executor::block_on(self.set_message_signature(signature_params, signing_key, signature_name, req_for_param))
556 }
557
558 fn set_message_signatures_sync<T, B>(
559 &mut self,
560 params_key_name: &[(&HttpSignatureParams, &T, Option<&str>)],
561 req_for_param: Option<&Request<B>>,
562 ) -> Result<(), Self::Error>
563 where
564 Self: Sized,
565 T: SigningKey + Sync,
566 B: Sync,
567 {
568 futures::executor::block_on(self.set_message_signatures(params_key_name, req_for_param))
569 }
570
571 fn verify_message_signature_sync<T, B>(
572 &self,
573 verifying_key: &T,
574 key_id: Option<&str>,
575 req_for_param: Option<&Request<B>>,
576 ) -> Result<SignatureName, Self::Error>
577 where
578 Self: Sized,
579 T: VerifyingKey + Sync,
580 B: Sync,
581 {
582 futures::executor::block_on(self.verify_message_signature(verifying_key, key_id, req_for_param))
583 }
584
585 fn verify_message_signatures_sync<T, B>(
586 &self,
587 key_and_id: &[(&T, Option<&str>)],
588 req_for_param: Option<&Request<B>>,
589 ) -> Result<Vec<Result<SignatureName, Self::Error>>, Self::Error>
590 where
591 Self: Sized,
592 T: VerifyingKey + Sync,
593 B: Sync,
594 {
595 futures::executor::block_on(self.verify_message_signatures(key_and_id, req_for_param))
596 }
597}
598
599fn has_message_signature_inner(headers: &HeaderMap) -> bool {
603 headers.contains_key("signature") && headers.contains_key("signature-input")
604}
605
606fn get_alg_key_ids_inner<B>(
608 req_or_res: &RequestOrResponse<B>,
609) -> HyperSigResult<IndexMap<SignatureName, (Option<AlgorithmName>, Option<KeyId>)>> {
610 let signature_headers_map = extract_signature_headers_with_name(req_or_res)?;
611 let res = signature_headers_map
612 .iter()
613 .map(|(name, headers)| {
614 let alg = headers
616 .signature_params()
617 .alg
618 .clone()
619 .map(|a| AlgorithmName::from_str(&a))
620 .transpose()
621 .ok()
622 .flatten();
623 let key_id = headers.signature_params().keyid.clone();
624 (name.clone(), (alg, key_id))
625 })
626 .collect();
627 Ok(res)
628}
629
630fn get_signature_params_inner<B>(
632 req_or_res: &RequestOrResponse<B>,
633) -> HyperSigResult<IndexMap<SignatureName, HttpSignatureParams>> {
634 let signature_headers_map = extract_signature_headers_with_name(req_or_res)?;
635 let res = signature_headers_map
636 .iter()
637 .map(|(name, headers)| (name.clone(), headers.signature_params().clone()))
638 .collect();
639 Ok(res)
640}
641
642fn extract_signatures_inner<B1, B2>(
644 req_or_res: &RequestOrResponse<B1>,
645 req_for_param: Option<&Request<B2>>,
646) -> HyperSigResult<IndexMap<SignatureName, (HttpSignatureBase, HttpSignatureHeaders)>> {
647 let signature_headers_map = extract_signature_headers_with_name(req_or_res)?;
648 let extracted = signature_headers_map
649 .iter()
650 .filter_map(|(name, headers)| {
651 build_signature_base(req_or_res, headers.signature_params(), req_for_param)
652 .ok()
653 .map(|base| (name.clone(), (base, headers.clone())))
654 })
655 .collect();
656 Ok(extracted)
657}
658
659async fn verify_message_signatures_inner<T>(
661 map_signature_with_base: &IndexMap<String, (HttpSignatureBase, HttpSignatureHeaders)>,
662 key_and_id: &[(&T, Option<&str>)],
663) -> HyperSigResult<Vec<HyperSigResult<SignatureName>>>
664where
665 T: VerifyingKey + Sync,
666{
667 let res_fut = key_and_id.iter().map(|(key, key_id)| {
669 let filtered = if let Some(key_id) = key_id {
670 map_signature_with_base
671 .iter()
672 .filter(|(_, (base, _))| base.keyid() == Some(key_id))
673 .collect::<IndexMap<_, _>>()
674 } else {
675 map_signature_with_base.iter().collect()
676 };
677
678 async move {
680 if filtered.is_empty() {
681 return Err(HyperSigError::NoSignatureHeaders(
682 "No signature as appropriate target for verification".to_string(),
683 ));
684 }
685 let successful_sig_names = filtered
687 .iter()
688 .filter_map(|(&name, (base, headers))| base.verify_signature_headers(*key, headers).ok().map(|_| name.clone()))
689 .collect::<IndexSet<_>>();
690 if !successful_sig_names.is_empty() {
691 Ok(successful_sig_names.first().unwrap().clone())
692 } else {
693 Err(HyperSigError::InvalidSignature(
694 "Invalid signature for the verifying key".to_string(),
695 ))
696 }
697 }
698 });
699 let res = futures::future::join_all(res_fut).await;
700 Ok(res)
701}
702
703enum RequestOrResponse<'a, B> {
707 Request(&'a Request<B>),
708 Response(&'a Response<B>),
709}
710
711impl<B> RequestOrResponse<'_, B> {
712 fn method(&self) -> HyperSigResult<&http::Method> {
713 match self {
714 RequestOrResponse::Request(req) => Ok(req.method()),
715 _ => Err(HyperSigError::InvalidComponentName(
716 "`method` is only for request".to_string(),
717 )),
718 }
719 }
720
721 fn uri(&self) -> HyperSigResult<&http::Uri> {
722 match self {
723 RequestOrResponse::Request(req) => Ok(req.uri()),
724 _ => Err(HyperSigError::InvalidComponentName("`uri` is only for request".to_string())),
725 }
726 }
727
728 fn headers(&self) -> &HeaderMap {
729 match self {
730 RequestOrResponse::Request(req) => req.headers(),
731 RequestOrResponse::Response(res) => res.headers(),
732 }
733 }
734
735 fn status(&self) -> HyperSigResult<http::StatusCode> {
736 match self {
737 RequestOrResponse::Response(res) => Ok(res.status()),
738 _ => Err(HyperSigError::InvalidComponentName(
739 "`status` is only for response".to_string(),
740 )),
741 }
742 }
743}
744
745fn extract_signature_headers_with_name<B>(req_or_res: &RequestOrResponse<B>) -> HyperSigResult<HttpSignatureHeadersMap> {
747 let headers = req_or_res.headers();
748 if !(headers.contains_key("signature-input") && headers.contains_key("signature")) {
749 return Err(HyperSigError::NoSignatureHeaders(
750 "The request does not have signature and signature-input headers".to_string(),
751 ));
752 };
753
754 let signature_input_strings = headers
755 .get_all("signature-input")
756 .iter()
757 .map(|v| v.to_str())
758 .collect::<Result<Vec<_>, _>>()?
759 .join(", ");
760 let signature_strings = headers
761 .get_all("signature")
762 .iter()
763 .map(|v| v.to_str())
764 .collect::<Result<Vec<_>, _>>()?
765 .join(", ");
766
767 let signature_headers = HttpSignatureHeaders::try_parse(&signature_strings, &signature_input_strings)?;
768 Ok(signature_headers)
769}
770
771fn build_signature_base<B1, B2>(
776 req_or_res: &RequestOrResponse<B1>,
777 signature_params: &HttpSignatureParams,
778 req_for_param: Option<&Request<B2>>,
779) -> HyperSigResult<HttpSignatureBase> {
780 let component_lines = signature_params
781 .covered_components
782 .iter()
783 .map(|component_id| {
784 if component_id.params.0.contains(&HttpMessageComponentParam::Req) {
785 if matches!(req_or_res, RequestOrResponse::Request(_)) {
786 return Err(HyperSigError::InvalidComponentParam(
787 "`req` is not allowed in request".to_string(),
788 ));
789 }
790 if req_for_param.is_none() {
791 return Err(HyperSigError::InvalidComponentParam(
792 "`req` is required for the param".to_string(),
793 ));
794 }
795 let req = RequestOrResponse::Request(req_for_param.unwrap());
796 extract_http_message_component(&req, component_id)
797 } else {
798 extract_http_message_component(req_or_res, component_id)
799 }
800 })
801 .collect::<Result<Vec<_>, _>>()?;
802
803 HttpSignatureBase::try_new(&component_lines, signature_params).map_err(|e| e.into())
804}
805
806fn extract_http_field<B>(req_or_res: &RequestOrResponse<B>, id: &HttpMessageComponentId) -> HyperSigResult<HttpMessageComponent> {
808 let HttpMessageComponentName::HttpField(header_name) = &id.name else {
809 return Err(HyperSigError::InvalidComponentName(
810 "invalid http message component name as http field".to_string(),
811 ));
812 };
813 let headers = match req_or_res {
814 RequestOrResponse::Request(req) => req.headers(),
815 RequestOrResponse::Response(res) => res.headers(),
816 };
817
818 let field_values = headers
819 .get_all(header_name)
820 .iter()
821 .map(|v| v.to_str().map(|s| s.to_owned()))
822 .collect::<Result<Vec<_>, _>>()?;
823
824 HttpMessageComponent::try_from((id, field_values.as_slice())).map_err(|e| e.into())
825}
826
827fn extract_derived_component<B>(
829 req_or_res: &RequestOrResponse<B>,
830 id: &HttpMessageComponentId,
831) -> HyperSigResult<HttpMessageComponent> {
832 let HttpMessageComponentName::Derived(derived_id) = &id.name else {
833 return Err(HyperSigError::InvalidComponentName(
834 "invalid http message component name as derived component".to_string(),
835 ));
836 };
837 id.params.0.iter().try_for_each(|param| match param {
842 HttpMessageComponentParam::Name(_) if matches!(derived_id, DerivedComponentName::QueryParam) => Ok(()),
843 HttpMessageComponentParam::Name(_) => Err(HyperSigError::InvalidComponentParam(
844 "`name` parameter is only allowed for `@query-param`".to_string(),
845 )),
846 HttpMessageComponentParam::Req if matches!(req_or_res, RequestOrResponse::Request(_)) => Ok(()),
851 HttpMessageComponentParam::Req => Err(HyperSigError::InvalidComponentParam(
852 "`req`-tagged component must be extracted from the source request".to_string(),
853 )),
854 _ => Err(HyperSigError::InvalidComponentParam(format!(
855 "parameter `{}` is not allowed on derived components",
856 String::from(param.clone())
857 ))),
858 })?;
859
860 match req_or_res {
861 RequestOrResponse::Request(_) => {
862 if matches!(derived_id, DerivedComponentName::Status) {
863 return Err(HyperSigError::InvalidComponentName(
864 "`status` is only for response".to_string(),
865 ));
866 }
867 }
868 RequestOrResponse::Response(_) => {
869 let has_req = id.params.0.contains(&HttpMessageComponentParam::Req);
870 if !matches!(derived_id, DerivedComponentName::Status)
873 && !matches!(derived_id, DerivedComponentName::SignatureParams)
874 && !has_req
875 {
876 return Err(HyperSigError::InvalidComponentName(
877 "derived components other than `@status` and `@signature-params` require `req` parameter for response".to_string(),
878 ));
879 }
880 if matches!(derived_id, DerivedComponentName::Status) && has_req {
882 return Err(HyperSigError::InvalidComponentParam(
883 "`@status` does not accept `req` parameter".to_string(),
884 ));
885 }
886 }
887 }
888
889 let field_values: Vec<String> = match derived_id {
890 DerivedComponentName::Method => vec![req_or_res.method()?.as_str().to_string()],
891 DerivedComponentName::TargetUri => vec![req_or_res.uri()?.to_string()],
892 DerivedComponentName::Authority => vec![req_or_res.uri()?.authority().map(|s| s.to_string()).unwrap_or("".to_string())],
893 DerivedComponentName::Scheme => vec![req_or_res.uri()?.scheme_str().unwrap_or("").to_string()],
894 DerivedComponentName::RequestTarget => match *req_or_res.method()? {
895 http::Method::CONNECT => vec![req_or_res.uri()?.authority().map(|s| s.to_string()).unwrap_or("".to_string())],
896 http::Method::OPTIONS => vec!["*".to_string()],
897 _ => vec![req_or_res
898 .uri()?
899 .path_and_query()
900 .map(|s| s.to_string())
901 .unwrap_or("".to_string())],
902 },
903 DerivedComponentName::Path => vec![{
904 let p = req_or_res.uri()?.path();
905 if p.is_empty() {
906 "/".to_string()
907 } else {
908 p.to_string()
909 }
910 }],
911 DerivedComponentName::Query => vec![req_or_res.uri()?.query().map(|v| format!("?{v}")).unwrap_or("?".to_string())],
912 DerivedComponentName::QueryParam => {
913 let query = req_or_res.uri()?.query().unwrap_or("");
914 query
915 .split('&')
916 .filter(|s| !s.is_empty())
917 .map(|s| s.to_string())
918 .collect::<Vec<_>>()
919 }
920 DerivedComponentName::Status => vec![req_or_res.status()?.as_str().to_string()],
921 DerivedComponentName::SignatureParams => req_or_res
922 .headers()
923 .get_all("signature-input")
924 .iter()
925 .map(|v| v.to_str().unwrap_or("").to_string())
926 .collect::<Vec<_>>(),
927 };
928
929 HttpMessageComponent::try_from((id, field_values.as_slice())).map_err(|e| e.into())
930}
931
932fn extract_http_message_component<B>(
935 req_or_res: &RequestOrResponse<B>,
936 target_component_id: &HttpMessageComponentId,
937) -> HyperSigResult<HttpMessageComponent> {
938 match &target_component_id.name {
939 HttpMessageComponentName::HttpField(_) => extract_http_field(req_or_res, target_component_id),
940 HttpMessageComponentName::Derived(_) => extract_derived_component(req_or_res, target_component_id),
941 }
942}
943
944#[cfg(test)]
946#[path = "hyper_http_tests.rs"]
947mod tests;