1use ntex::{
78 http::{
79 header::{HeaderName, HeaderValue},
80 HeaderMap,
81 },
82 web::{WebRequest, WebResponse},
83 Middleware, Service, ServiceCtx,
84};
85
86use helmet_core::Helmet as HelmetCore;
87
88pub use helmet_core::*;
90
91pub struct HelmetMiddleware<S> {
92 service: S,
93 headers: HeaderMap,
94}
95
96impl<S, E> Service<WebRequest<E>> for HelmetMiddleware<S>
97where
98 S: Service<WebRequest<E>, Response = WebResponse>,
99 E: 'static,
100{
101 type Response = WebResponse;
102 type Error = S::Error;
103
104 async fn call(
105 &self,
106 req: WebRequest<E>,
107 ctx: ServiceCtx<'_, Self>,
108 ) -> Result<Self::Response, Self::Error> {
109 let mut res = ctx.call(&self.service, req).await?;
110
111 for (name, value) in self.headers.iter() {
113 res.headers_mut().append(name.clone(), value.clone());
114 }
115
116 Ok(res)
117 }
118}
119
120#[derive(Default)]
125pub struct Helmet(HelmetCore);
126
127#[allow(clippy::should_implement_trait)]
128impl Helmet {
129 pub fn new() -> Self {
130 Self(HelmetCore::new())
131 }
132
133 pub fn add(self, middleware: impl Into<helmet_core::Header>) -> Self {
134 Self(self.0.add(middleware))
135 }
136}
137
138impl<S> Middleware<S> for Helmet {
139 type Service = HelmetMiddleware<S>;
140
141 fn create(&self, service: S) -> Self::Service {
142 let mut headers = HeaderMap::new();
143 for header in self.0.headers.iter() {
144 let name = HeaderName::try_from(header.0).expect("invalid header name");
145 let value = HeaderValue::from_str(&header.1).expect("invalid header value");
146 headers.append(name, value);
147 }
148
149 HelmetMiddleware { service, headers }
150 }
151}
152
153#[cfg(test)]
154mod tests {
155 use ntex::{
156 web::test::{ok_service, TestRequest},
157 Pipeline,
158 };
159
160 use helmet_core::{
161 ContentSecurityPolicy, CrossOriginEmbedderPolicy, CrossOriginOpenerPolicy,
162 CrossOriginResourcePolicy, OriginAgentCluster, ReferrerPolicy, StrictTransportSecurity,
163 XContentTypeOptions, XDNSPrefetchControl, XDownloadOptions, XFrameOptions,
164 XPermittedCrossDomainPolicies, XPoweredBy, XXSSProtection,
165 };
166
167 use super::*;
168
169 #[ntex::test]
170 async fn test_cross_origin_embedder_policy_unsafe_none() {
171 let mw = Pipeline::new(
172 Helmet::new()
173 .add(CrossOriginEmbedderPolicy::unsafe_none())
174 .create(ok_service()),
175 );
176
177 let req = TestRequest::default().to_srv_request();
178 let resp = mw.call(req).await.unwrap();
179 assert_eq!(
180 resp.headers().get("Cross-Origin-Embedder-Policy").unwrap(),
181 "unsafe-none"
182 );
183 }
184
185 #[ntex::test]
186 async fn test_cross_origin_embedder_policy_require_corp() {
187 let mw = Pipeline::new(
188 Helmet::new()
189 .add(CrossOriginEmbedderPolicy::require_corp())
190 .create(ok_service()),
191 );
192
193 let req = TestRequest::default().to_srv_request();
194 let resp = mw.call(req).await.unwrap();
195 assert_eq!(
196 resp.headers().get("Cross-Origin-Embedder-Policy").unwrap(),
197 "require-corp"
198 );
199 }
200
201 #[ntex::test]
202 async fn test_cross_origin_embedder_policy_credentialless() {
203 let mw = Pipeline::new(
204 Helmet::new()
205 .add(CrossOriginEmbedderPolicy::credentialless())
206 .create(ok_service()),
207 );
208
209 let req = TestRequest::default().to_srv_request();
210 let resp = mw.call(req).await.unwrap();
211 assert_eq!(
212 resp.headers().get("Cross-Origin-Embedder-Policy").unwrap(),
213 "credentialless"
214 );
215 }
216
217 #[ntex::test]
218 async fn test_cross_origin_opener_policy_same_origin() {
219 let mw = Pipeline::new(
220 Helmet::new()
221 .add(CrossOriginOpenerPolicy::same_origin())
222 .create(ok_service()),
223 );
224
225 let req = TestRequest::default().to_srv_request();
226 let resp = mw.call(req).await.unwrap();
227 assert_eq!(
228 resp.headers().get("Cross-Origin-Opener-Policy").unwrap(),
229 "same-origin"
230 );
231 }
232
233 #[ntex::test]
234 async fn test_cross_origin_opener_policy_same_origin_allow_popups() {
235 let mw = Pipeline::new(
236 Helmet::new()
237 .add(CrossOriginOpenerPolicy::same_origin_allow_popups())
238 .create(ok_service()),
239 );
240
241 let req = TestRequest::default().to_srv_request();
242 let resp = mw.call(req).await.unwrap();
243 assert_eq!(
244 resp.headers().get("Cross-Origin-Opener-Policy").unwrap(),
245 "same-origin-allow-popups"
246 );
247 }
248
249 #[ntex::test]
250 async fn test_cross_origin_opener_policy_unsafe_none() {
251 let mw = Pipeline::new(
252 Helmet::new()
253 .add(CrossOriginOpenerPolicy::unsafe_none())
254 .create(ok_service()),
255 );
256
257 let req = TestRequest::default().to_srv_request();
258 let resp = mw.call(req).await.unwrap();
259 assert_eq!(
260 resp.headers().get("Cross-Origin-Opener-Policy").unwrap(),
261 "unsafe-none"
262 );
263 }
264
265 #[ntex::test]
266 async fn test_cross_origin_resource_policy_same_origin() {
267 let mw = Pipeline::new(
268 Helmet::new()
269 .add(CrossOriginResourcePolicy::same_origin())
270 .create(ok_service()),
271 );
272
273 let req = TestRequest::default().to_srv_request();
274 let resp = mw.call(req).await.unwrap();
275 assert_eq!(
276 resp.headers().get("Cross-Origin-Resource-Policy").unwrap(),
277 "same-origin"
278 );
279 }
280
281 #[ntex::test]
282 async fn test_cross_origin_resource_policy_cross_origin() {
283 let mw = Pipeline::new(
284 Helmet::new()
285 .add(CrossOriginResourcePolicy::cross_origin())
286 .create(ok_service()),
287 );
288
289 let req = TestRequest::default().to_srv_request();
290 let resp = mw.call(req).await.unwrap();
291 assert_eq!(
292 resp.headers().get("Cross-Origin-Resource-Policy").unwrap(),
293 "cross-origin"
294 );
295 }
296
297 #[ntex::test]
298 async fn test_cross_origin_resource_policy_same_site() {
299 let mw = Pipeline::new(
300 Helmet::new()
301 .add(CrossOriginResourcePolicy::same_site())
302 .create(ok_service()),
303 );
304
305 let req = TestRequest::default().to_srv_request();
306 let resp = mw.call(req).await.unwrap();
307 assert_eq!(
308 resp.headers().get("Cross-Origin-Resource-Policy").unwrap(),
309 "same-site"
310 );
311 }
312
313 #[ntex::test]
314 async fn test_origin_agent_cluster_prefer_mobile() {
315 let mw = Pipeline::new(
316 Helmet::new()
317 .add(OriginAgentCluster::new(true))
318 .create(ok_service()),
319 );
320
321 let req = TestRequest::default().to_srv_request();
322 let resp = mw.call(req).await.unwrap();
323 assert_eq!(
324 resp.headers()
325 .get("Origin-Agent-Cluster")
326 .unwrap()
327 .to_str()
328 .unwrap(),
329 "?1"
330 );
331 }
332
333 #[ntex::test]
334 async fn test_origin_agent_cluster_not_prefer_mobile() {
335 let mw = Pipeline::new(
336 Helmet::new()
337 .add(OriginAgentCluster::new(false))
338 .create(ok_service()),
339 );
340
341 let req = TestRequest::default().to_srv_request();
342 let resp = mw.call(req).await.unwrap();
343 assert_eq!(
344 resp.headers()
345 .get("Origin-Agent-Cluster")
346 .unwrap()
347 .to_str()
348 .unwrap(),
349 "?0"
350 );
351 }
352
353 #[ntex::test]
354 async fn test_referrer_policy_no_referrer() {
355 let mw = Pipeline::new(
356 Helmet::new()
357 .add(ReferrerPolicy::no_referrer())
358 .create(ok_service()),
359 );
360
361 let req = TestRequest::default().to_srv_request();
362 let resp = mw.call(req).await.unwrap();
363 assert_eq!(
364 resp.headers().get("Referrer-Policy").unwrap(),
365 "no-referrer"
366 );
367 }
368
369 #[ntex::test]
370 async fn test_referrer_policy_no_referrer_when_downgrade() {
371 let mw = Pipeline::new(
372 Helmet::new()
373 .add(ReferrerPolicy::no_referrer_when_downgrade())
374 .create(ok_service()),
375 );
376
377 let req = TestRequest::default().to_srv_request();
378 let resp = mw.call(req).await.unwrap();
379 assert_eq!(
380 resp.headers().get("Referrer-Policy").unwrap(),
381 "no-referrer-when-downgrade"
382 );
383 }
384
385 #[ntex::test]
386 async fn test_referrer_policy_origin() {
387 let mw = Pipeline::new(
388 Helmet::new()
389 .add(ReferrerPolicy::origin())
390 .create(ok_service()),
391 );
392
393 let req = TestRequest::default().to_srv_request();
394 let resp = mw.call(req).await.unwrap();
395 assert_eq!(resp.headers().get("Referrer-Policy").unwrap(), "origin");
396 }
397
398 #[ntex::test]
399 async fn test_referrer_policy_origin_when_cross_origin() {
400 let mw = Pipeline::new(
401 Helmet::new()
402 .add(ReferrerPolicy::origin_when_cross_origin())
403 .create(ok_service()),
404 );
405
406 let req = TestRequest::default()
407 .header("Origin", "https://example.com")
408 .to_srv_request();
409 let resp = mw.call(req).await.unwrap();
410 assert_eq!(
411 resp.headers().get("Referrer-Policy").unwrap(),
412 "origin-when-cross-origin"
413 );
414 }
415
416 #[ntex::test]
417 async fn test_referrer_policy_same_origin() {
418 let mw = Pipeline::new(
419 Helmet::new()
420 .add(ReferrerPolicy::same_origin())
421 .create(ok_service()),
422 );
423
424 let req = TestRequest::default()
425 .header("Origin", "https://example.com")
426 .to_srv_request();
427 let resp = mw.call(req).await.unwrap();
428 assert_eq!(
429 resp.headers().get("Referrer-Policy").unwrap(),
430 "same-origin"
431 );
432 }
433
434 #[ntex::test]
435 async fn test_referrer_policy_strict_origin() {
436 let mw = Pipeline::new(
437 Helmet::new()
438 .add(ReferrerPolicy::strict_origin())
439 .create(ok_service()),
440 );
441
442 let req = TestRequest::default()
443 .header("Origin", "https://example.com")
444 .to_srv_request();
445 let resp = mw.call(req).await.unwrap();
446 assert_eq!(
447 resp.headers().get("Referrer-Policy").unwrap(),
448 "strict-origin"
449 );
450 }
451
452 #[ntex::test]
453 async fn test_referrer_policy_strict_origin_when_cross_origin() {
454 let mw = Pipeline::new(
455 Helmet::new()
456 .add(ReferrerPolicy::strict_origin_when_cross_origin())
457 .create(ok_service()),
458 );
459
460 let req = TestRequest::default()
461 .header("Origin", "https://example.com")
462 .to_srv_request();
463 let resp = mw.call(req).await.unwrap();
464 assert_eq!(
465 resp.headers().get("Referrer-Policy").unwrap(),
466 "strict-origin-when-cross-origin"
467 );
468 }
469
470 #[ntex::test]
471 async fn test_referrer_policy_unsafe_url() {
472 let mw = Pipeline::new(
473 Helmet::new()
474 .add(ReferrerPolicy::unsafe_url())
475 .create(ok_service()),
476 );
477
478 let req = TestRequest::default()
479 .header("Origin", "https://example.com")
480 .to_srv_request();
481 let resp = mw.call(req).await.unwrap();
482 assert_eq!(resp.headers().get("Referrer-Policy").unwrap(), "unsafe-url");
483 }
484
485 #[ntex::test]
486 async fn test_strict_transport_security_max_age() {
487 let mw = Pipeline::new(
488 Helmet::new()
489 .add(StrictTransportSecurity::new().max_age(31536000))
490 .create(ok_service()),
491 );
492
493 let req = TestRequest::default().to_srv_request();
494 let resp = mw.call(req).await.unwrap();
495
496 assert_eq!(
497 resp.headers()
498 .get("Strict-Transport-Security")
499 .unwrap()
500 .to_str()
501 .unwrap(),
502 "max-age=31536000"
503 );
504 }
505
506 #[ntex::test]
507 async fn test_strict_transport_security_max_age_include_sub_domains() {
508 let mw = Pipeline::new(
509 Helmet::new()
510 .add(
511 StrictTransportSecurity::new()
512 .max_age(31536000)
513 .include_sub_domains(),
514 )
515 .create(ok_service()),
516 );
517
518 let req = TestRequest::default().to_srv_request();
519 let resp = mw.call(req).await.unwrap();
520
521 assert_eq!(
522 resp.headers()
523 .get("Strict-Transport-Security")
524 .unwrap()
525 .to_str()
526 .unwrap(),
527 "max-age=31536000; includeSubDomains"
528 );
529 }
530
531 #[ntex::test]
532 async fn test_strict_transport_security_max_age_preload() {
533 let mw = Pipeline::new(
534 Helmet::new()
535 .add(StrictTransportSecurity::new().max_age(31536000).preload())
536 .create(ok_service()),
537 );
538
539 let req = TestRequest::default().to_srv_request();
540 let resp = mw.call(req).await.unwrap();
541
542 assert_eq!(
543 resp.headers()
544 .get("Strict-Transport-Security")
545 .unwrap()
546 .to_str()
547 .unwrap(),
548 "max-age=31536000; preload"
549 );
550 }
551
552 #[ntex::test]
553 async fn test_strict_transport_security_max_age_include_sub_domains_preload() {
554 let mw = Pipeline::new(
555 Helmet::new()
556 .add(
557 StrictTransportSecurity::new()
558 .max_age(31536000)
559 .include_sub_domains()
560 .preload(),
561 )
562 .create(ok_service()),
563 );
564
565 let req = TestRequest::default().to_srv_request();
566 let resp = mw.call(req).await.unwrap();
567
568 assert_eq!(
569 resp.headers()
570 .get("Strict-Transport-Security")
571 .unwrap()
572 .to_str()
573 .unwrap(),
574 "max-age=31536000; includeSubDomains; preload"
575 );
576 }
577
578 #[ntex::test]
579 async fn test_x_content_type_options_nosniff() {
580 let mw = Pipeline::new(
581 Helmet::new()
582 .add(XContentTypeOptions::nosniff())
583 .create(ok_service()),
584 );
585
586 let req = TestRequest::default().to_srv_request();
587 let resp = mw.call(req).await.unwrap();
588
589 assert_eq!(
590 resp.headers()
591 .get("X-Content-Type-Options")
592 .unwrap()
593 .to_str()
594 .unwrap(),
595 "nosniff"
596 );
597 }
598
599 #[ntex::test]
600 async fn test_x_dns_prefetch_control_off() {
601 let mw = Pipeline::new(
602 Helmet::new()
603 .add(XDNSPrefetchControl::off())
604 .create(ok_service()),
605 );
606
607 let req = TestRequest::default().to_srv_request();
608 let resp = mw.call(req).await.unwrap();
609
610 assert_eq!(
611 resp.headers()
612 .get("X-DNS-Prefetch-Control")
613 .unwrap()
614 .to_str()
615 .unwrap(),
616 "off"
617 );
618 }
619
620 #[ntex::test]
621 async fn test_x_dns_prefetch_control_on() {
622 let mw = Pipeline::new(
623 Helmet::new()
624 .add(XDNSPrefetchControl::on())
625 .create(ok_service()),
626 );
627
628 let req = TestRequest::default().to_srv_request();
629 let resp = mw.call(req).await.unwrap();
630
631 assert_eq!(
632 resp.headers()
633 .get("X-DNS-Prefetch-Control")
634 .unwrap()
635 .to_str()
636 .unwrap(),
637 "on"
638 );
639 }
640
641 #[ntex::test]
642 async fn test_x_download_options_noopen() {
643 let mw = Pipeline::new(
644 Helmet::new()
645 .add(XDownloadOptions::noopen())
646 .create(ok_service()),
647 );
648
649 let req = TestRequest::default().to_srv_request();
650 let resp = mw.call(req).await.unwrap();
651
652 assert_eq!(
653 resp.headers()
654 .get("X-Download-Options")
655 .unwrap()
656 .to_str()
657 .unwrap(),
658 "noopen"
659 );
660 }
661
662 #[ntex::test]
663 async fn test_x_frame_options_deny() {
664 let mw = Pipeline::new(
665 Helmet::new()
666 .add(XFrameOptions::deny())
667 .create(ok_service()),
668 );
669
670 let req = TestRequest::default()
671 .header("Origin", "https://example.com")
672 .to_srv_request();
673 let resp = mw.call(req).await.unwrap();
674
675 assert_eq!(
676 resp.headers()
677 .get("X-Frame-Options")
678 .unwrap()
679 .to_str()
680 .unwrap(),
681 "DENY"
682 );
683 }
684
685 #[ntex::test]
686 async fn test_x_frame_options_same_origin() {
687 let mw = Pipeline::new(
688 Helmet::new()
689 .add(XFrameOptions::same_origin())
690 .create(ok_service()),
691 );
692
693 let req = TestRequest::default()
694 .header("Origin", "https://example.com")
695 .to_srv_request();
696 let resp = mw.call(req).await.unwrap();
697
698 assert_eq!(
699 resp.headers()
700 .get("X-Frame-Options")
701 .unwrap()
702 .to_str()
703 .unwrap(),
704 "SAMEORIGIN"
705 );
706 }
707
708 #[ntex::test]
709 async fn test_x_frame_options_allow_from() {
710 let mw = Pipeline::new(
711 Helmet::new()
712 .add(XFrameOptions::allow_from("https://example.com"))
713 .create(ok_service()),
714 );
715
716 let req = TestRequest::default()
717 .header("Origin", "https://example.com")
718 .to_srv_request();
719 let resp = mw.call(req).await.unwrap();
720
721 assert_eq!(
722 resp.headers()
723 .get("X-Frame-Options")
724 .unwrap()
725 .to_str()
726 .unwrap(),
727 "ALLOW-FROM https://example.com"
728 );
729 }
730
731 #[ntex::test]
732 async fn test_x_permitted_cross_domain_policies_none() {
733 let mw = Pipeline::new(
734 Helmet::new()
735 .add(XPermittedCrossDomainPolicies::none())
736 .create(ok_service()),
737 );
738
739 let req = TestRequest::default().to_srv_request();
740 let resp = mw.call(req).await.unwrap();
741 assert_eq!(
742 resp.headers()
743 .get("X-Permitted-Cross-Domain-Policies")
744 .unwrap()
745 .to_str()
746 .unwrap(),
747 "none"
748 );
749 }
750
751 #[ntex::test]
752 async fn test_x_permitted_cross_domain_policies_master_only() {
753 let mw = Pipeline::new(
754 Helmet::new()
755 .add(XPermittedCrossDomainPolicies::master_only())
756 .create(ok_service()),
757 );
758
759 let req = TestRequest::default().to_srv_request();
760 let resp = mw.call(req).await.unwrap();
761 assert_eq!(
762 resp.headers()
763 .get("X-Permitted-Cross-Domain-Policies")
764 .unwrap()
765 .to_str()
766 .unwrap(),
767 "master-only"
768 );
769 }
770
771 #[ntex::test]
772 async fn test_x_permitted_cross_domain_policies_by_content_type() {
773 let mw = Pipeline::new(
774 Helmet::new()
775 .add(XPermittedCrossDomainPolicies::by_content_type())
776 .create(ok_service()),
777 );
778
779 let req = TestRequest::default().to_srv_request();
780 let resp = mw.call(req).await.unwrap();
781 assert_eq!(
782 resp.headers()
783 .get("X-Permitted-Cross-Domain-Policies")
784 .unwrap()
785 .to_str()
786 .unwrap(),
787 "by-content-type"
788 );
789 }
790
791 #[ntex::test]
792 async fn test_x_permitted_cross_domain_policies_by_ftp_filename() {
793 let mw = Pipeline::new(
794 Helmet::new()
795 .add(XPermittedCrossDomainPolicies::by_ftp_filename())
796 .create(ok_service()),
797 );
798
799 let req = TestRequest::default()
800 .header("Origin", "https://example.com")
801 .to_srv_request();
802 let resp = mw.call(req).await.unwrap();
803 assert_eq!(
804 resp.headers()
805 .get("X-Permitted-Cross-Domain-Policies")
806 .unwrap()
807 .to_str()
808 .unwrap(),
809 "by-ftp-filename"
810 );
811 }
812
813 #[ntex::test]
814 async fn test_x_permitted_cross_domain_policies_all() {
815 let mw = Pipeline::new(
816 Helmet::new()
817 .add(XPermittedCrossDomainPolicies::all())
818 .create(ok_service()),
819 );
820
821 let req = TestRequest::default().to_srv_request();
822 let resp = mw.call(req).await.unwrap();
823 assert_eq!(
824 resp.headers()
825 .get("X-Permitted-Cross-Domain-Policies")
826 .unwrap()
827 .to_str()
828 .unwrap(),
829 "all"
830 );
831 }
832
833 #[ntex::test]
834 async fn test_x_xss_protection_zero() {
835 let mw = Pipeline::new(
836 Helmet::new()
837 .add(XXSSProtection::off())
838 .create(ok_service()),
839 );
840
841 let req = TestRequest::default().to_srv_request();
842 let resp = mw.call(req).await.unwrap();
843
844 assert_eq!(resp.headers().get("X-XSS-Protection").unwrap(), "0");
845 }
846
847 #[ntex::test]
848 async fn test_x_xss_protection_one() {
849 let mw = Pipeline::new(Helmet::new().add(XXSSProtection::on()).create(ok_service()));
850
851 let req = TestRequest::default()
852 .header("Origin", "https://example.com")
853 .to_srv_request();
854 let resp = mw.call(req).await.unwrap();
855
856 assert_eq!(resp.headers().get("X-XSS-Protection").unwrap(), "1");
857 }
858
859 #[ntex::test]
860 async fn test_x_xss_protection_one_mode_block() {
861 let mw = Pipeline::new(
862 Helmet::new()
863 .add(XXSSProtection::on().mode_block())
864 .create(ok_service()),
865 );
866
867 let req = TestRequest::default().to_srv_request();
868 let resp = mw.call(req).await.unwrap();
869
870 assert_eq!(
871 resp.headers().get("X-XSS-Protection").unwrap(),
872 "1; mode=block"
873 );
874 }
875
876 #[ntex::test]
877 async fn test_x_xss_protection_one_mode_block_report() {
878 let mw = Pipeline::new(
879 Helmet::new()
880 .add(
881 XXSSProtection::on()
882 .mode_block()
883 .report("https://example.com/report-xss-attack"),
884 )
885 .create(ok_service()),
886 );
887
888 let req = TestRequest::default()
889 .header("Origin", "https://example.com")
890 .to_srv_request();
891 let resp = mw.call(req).await.unwrap();
892
893 assert_eq!(
894 resp.headers()
895 .get("X-XSS-Protection")
896 .unwrap()
897 .to_str()
898 .unwrap(),
899 "1; mode=block; report=https://example.com/report-xss-attack"
900 );
901 }
902
903 #[ntex::test]
904 async fn test_content_security_policy_default() {
905 let mw = Pipeline::new(
906 Helmet::new()
907 .add(ContentSecurityPolicy::default())
908 .create(ok_service()),
909 );
910
911 let req = TestRequest::default()
912 .header("Origin", "https://example.com")
913 .to_srv_request();
914 let resp = mw.call(req).await.unwrap();
915
916 assert_eq!(
917 resp.headers()
918 .get("Content-Security-Policy")
919 .unwrap()
920 .to_str()
921 .unwrap(),
922 "default-src 'self'; base-uri 'self'; font-src 'self' https: data:; form-action 'self'; frame-ancestors 'self'; img-src 'self' data:; object-src 'none'; script-src 'self'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; upgrade-insecure-requests"
923 );
924 }
925
926 #[ntex::test]
927 async fn test_x_powered_by() {
928 let mw = Pipeline::new(
929 Helmet::new()
930 .add(XPoweredBy::new("PHP 4.2.0"))
931 .create(ok_service()),
932 );
933
934 let req = TestRequest::default().to_srv_request();
935 let resp = mw.call(req).await.unwrap();
936
937 assert_eq!(resp.headers().get("X-Powered-By").unwrap(), "PHP 4.2.0");
938 }
939
940 #[ntex::test]
941 async fn test_content_security_policy_child_src() {
942 let mw = Pipeline::new(
943 Helmet::new()
944 .add(ContentSecurityPolicy::new().child_src(vec!["'self'", "https://youtube.com"]))
945 .create(ok_service()),
946 );
947
948 let req = TestRequest::default().to_srv_request();
949 let resp = mw.call(req).await.unwrap();
950
951 assert_eq!(
952 resp.headers()
953 .get("Content-Security-Policy")
954 .unwrap()
955 .to_str()
956 .unwrap(),
957 "child-src 'self' https://youtube.com"
958 );
959 }
960
961 #[ntex::test]
962 async fn test_content_security_policy_connect_src() {
963 let mw = Pipeline::new(
964 Helmet::new()
965 .add(
966 ContentSecurityPolicy::new().connect_src(vec!["'self'", "https://youtube.com"]),
967 )
968 .create(ok_service()),
969 );
970
971 let req = TestRequest::default().to_srv_request();
972 let resp = mw.call(req).await.unwrap();
973
974 assert_eq!(
975 resp.headers()
976 .get("Content-Security-Policy")
977 .unwrap()
978 .to_str()
979 .unwrap(),
980 "connect-src 'self' https://youtube.com"
981 );
982 }
983
984 #[ntex::test]
985 async fn test_content_security_policy_default_src() {
986 let mw = Pipeline::new(
987 Helmet::new()
988 .add(
989 ContentSecurityPolicy::new().default_src(vec!["'self'", "https://youtube.com"]),
990 )
991 .create(ok_service()),
992 );
993
994 let req = TestRequest::default().to_srv_request();
995 let resp = mw.call(req).await.unwrap();
996 assert_eq!(
997 resp.headers()
998 .get("Content-Security-Policy")
999 .unwrap()
1000 .to_str()
1001 .unwrap(),
1002 "default-src 'self' https://youtube.com"
1003 );
1004 }
1005
1006 #[ntex::test]
1007 async fn test_content_security_policy_font_src() {
1008 let mw = Pipeline::new(
1009 Helmet::new()
1010 .add(ContentSecurityPolicy::new().font_src(vec!["'self'", "https://youtube.com"]))
1011 .create(ok_service()),
1012 );
1013
1014 let req = TestRequest::default().to_srv_request();
1015 let resp = mw.call(req).await.unwrap();
1016 assert_eq!(
1017 resp.headers()
1018 .get("Content-Security-Policy")
1019 .unwrap()
1020 .to_str()
1021 .unwrap(),
1022 "font-src 'self' https://youtube.com"
1023 );
1024 }
1025
1026 #[ntex::test]
1027 async fn test_content_security_policy_frame_src() {
1028 let mw = Pipeline::new(
1029 Helmet::new()
1030 .add(ContentSecurityPolicy::new().frame_src(vec!["'self'", "https://youtube.com"]))
1031 .create(ok_service()),
1032 );
1033
1034 let req = TestRequest::default().to_srv_request();
1035 let resp = mw.call(req).await.unwrap();
1036 assert_eq!(
1037 resp.headers()
1038 .get("Content-Security-Policy")
1039 .unwrap()
1040 .to_str()
1041 .unwrap(),
1042 "frame-src 'self' https://youtube.com"
1043 );
1044 }
1045
1046 #[ntex::test]
1047 async fn test_content_security_policy_img_src() {
1048 let mw = Pipeline::new(
1049 Helmet::new()
1050 .add(ContentSecurityPolicy::new().img_src(vec!["'self'", "https://youtube.com"]))
1051 .create(ok_service()),
1052 );
1053
1054 let req = TestRequest::default().to_srv_request();
1055 let resp = mw.call(req).await.unwrap();
1056 assert_eq!(
1057 resp.headers().get("Content-Security-Policy").unwrap(),
1058 "img-src 'self' https://youtube.com"
1059 );
1060 }
1061
1062 #[ntex::test]
1063 async fn test_content_security_policy_manifest_src() {
1064 let mw = Pipeline::new(
1065 Helmet::new()
1066 .add(
1067 ContentSecurityPolicy::new()
1068 .manifest_src(vec!["'self'", "https://youtube.com"]),
1069 )
1070 .create(ok_service()),
1071 );
1072
1073 let req = TestRequest::default().to_srv_request();
1074 let resp = mw.call(req).await.unwrap();
1075 assert_eq!(
1076 resp.headers().get("Content-Security-Policy").unwrap(),
1077 "manifest-src 'self' https://youtube.com"
1078 );
1079 }
1080
1081 #[ntex::test]
1082 async fn test_content_security_policy_media_src() {
1083 let mw = Pipeline::new(
1084 Helmet::new()
1085 .add(ContentSecurityPolicy::new().media_src(vec!["'self'", "https://youtube.com"]))
1086 .create(ok_service()),
1087 );
1088
1089 let req = TestRequest::default().to_srv_request();
1090 let resp = mw.call(req).await.unwrap();
1091 assert_eq!(
1092 resp.headers().get("Content-Security-Policy").unwrap(),
1093 "media-src 'self' https://youtube.com"
1094 );
1095 }
1096
1097 #[ntex::test]
1098 async fn test_content_security_policy_object_src() {
1099 let mw = Pipeline::new(
1100 Helmet::new()
1101 .add(ContentSecurityPolicy::new().object_src(vec!["'self'", "https://youtube.com"]))
1102 .create(ok_service()),
1103 );
1104
1105 let req = TestRequest::default().to_srv_request();
1106 let resp = mw.call(req).await.unwrap();
1107 assert_eq!(
1108 resp.headers().get("Content-Security-Policy").unwrap(),
1109 "object-src 'self' https://youtube.com"
1110 );
1111 }
1112
1113 #[ntex::test]
1114 async fn test_content_security_policy_prefetch_src() {
1115 let mw = Pipeline::new(
1116 Helmet::new()
1117 .add(
1118 ContentSecurityPolicy::new()
1119 .prefetch_src(vec!["'self'", "https://youtube.com"]),
1120 )
1121 .create(ok_service()),
1122 );
1123
1124 let req = TestRequest::default().to_srv_request();
1125 let resp = mw.call(req).await.unwrap();
1126 assert_eq!(
1127 resp.headers().get("Content-Security-Policy").unwrap(),
1128 "prefetch-src 'self' https://youtube.com"
1129 );
1130 }
1131
1132 #[ntex::test]
1133 async fn test_content_security_policy_script_src() {
1134 let mw = Pipeline::new(
1135 Helmet::new()
1136 .add(ContentSecurityPolicy::new().script_src(vec!["'self'", "https://youtube.com"]))
1137 .create(ok_service()),
1138 );
1139
1140 let req = TestRequest::default().to_srv_request();
1141 let resp = mw.call(req).await.unwrap();
1142 assert_eq!(
1143 resp.headers().get("Content-Security-Policy").unwrap(),
1144 "script-src 'self' https://youtube.com"
1145 );
1146 }
1147
1148 #[ntex::test]
1149 async fn test_content_security_policy_script_src_elem() {
1150 let mw = Pipeline::new(
1151 Helmet::new()
1152 .add(
1153 ContentSecurityPolicy::new()
1154 .script_src_elem(vec!["'self'", "https://youtube.com"]),
1155 )
1156 .create(ok_service()),
1157 );
1158
1159 let req = TestRequest::default().to_srv_request();
1160 let resp = mw.call(req).await.unwrap();
1161 assert_eq!(
1162 resp.headers().get("Content-Security-Policy").unwrap(),
1163 "script-src-elem 'self' https://youtube.com"
1164 );
1165 }
1166
1167 #[ntex::test]
1168 async fn test_content_security_policy_script_src_attr() {
1169 let mw = Pipeline::new(
1170 Helmet::new()
1171 .add(
1172 ContentSecurityPolicy::new()
1173 .script_src_attr(vec!["'self'", "https://youtube.com"]),
1174 )
1175 .create(ok_service()),
1176 );
1177
1178 let req = TestRequest::default().to_srv_request();
1179 let resp = mw.call(req).await.unwrap();
1180 assert_eq!(
1181 resp.headers().get("Content-Security-Policy").unwrap(),
1182 "script-src-attr 'self' https://youtube.com"
1183 );
1184 }
1185
1186 #[ntex::test]
1187 async fn test_content_security_policy_style_src() {
1188 let mw = Pipeline::new(
1189 Helmet::new()
1190 .add(ContentSecurityPolicy::new().style_src(vec!["'self'", "https://youtube.com"]))
1191 .create(ok_service()),
1192 );
1193
1194 let req = TestRequest::default().to_srv_request();
1195 let resp = mw.call(req).await.unwrap();
1196 assert_eq!(
1197 resp.headers().get("Content-Security-Policy").unwrap(),
1198 "style-src 'self' https://youtube.com"
1199 );
1200 }
1201
1202 #[ntex::test]
1203 async fn test_content_security_policy_style_src_attr() {
1204 let mw = Pipeline::new(
1205 Helmet::new()
1206 .add(
1207 ContentSecurityPolicy::new()
1208 .style_src_attr(vec!["'self'", "https://youtube.com"]),
1209 )
1210 .create(ok_service()),
1211 );
1212
1213 let req = TestRequest::default().to_srv_request();
1214 let resp = mw.call(req).await.unwrap();
1215 assert_eq!(
1216 resp.headers().get("Content-Security-Policy").unwrap(),
1217 "style-src-attr 'self' https://youtube.com"
1218 );
1219 }
1220
1221 #[ntex::test]
1222 async fn test_content_security_policy_style_src_elem() {
1223 let mw = Pipeline::new(
1224 Helmet::new()
1225 .add(
1226 ContentSecurityPolicy::new()
1227 .style_src_elem(vec!["'self'", "https://youtube.com"]),
1228 )
1229 .create(ok_service()),
1230 );
1231
1232 let req = TestRequest::default().to_srv_request();
1233 let resp = mw.call(req).await.unwrap();
1234 assert_eq!(
1235 resp.headers().get("Content-Security-Policy").unwrap(),
1236 "style-src-elem 'self' https://youtube.com"
1237 );
1238 }
1239
1240 #[ntex::test]
1241 async fn test_content_security_policy_worker_src() {
1242 let mw = Pipeline::new(
1243 Helmet::new()
1244 .add(ContentSecurityPolicy::new().worker_src(vec!["'self'", "https://youtube.com"]))
1245 .create(ok_service()),
1246 );
1247
1248 let req = TestRequest::default().to_srv_request();
1249 let resp = mw.call(req).await.unwrap();
1250 assert_eq!(
1251 resp.headers().get("Content-Security-Policy").unwrap(),
1252 "worker-src 'self' https://youtube.com"
1253 );
1254 }
1255
1256 #[ntex::test]
1257 async fn test_content_security_policy_base_uri() {
1258 let mw = Pipeline::new(
1259 Helmet::new()
1260 .add(ContentSecurityPolicy::new().base_uri(vec!["'self'", "https://youtube.com"]))
1261 .create(ok_service()),
1262 );
1263
1264 let req = TestRequest::default().to_srv_request();
1265 let resp = mw.call(req).await.unwrap();
1266 assert_eq!(
1267 resp.headers().get("Content-Security-Policy").unwrap(),
1268 "base-uri 'self' https://youtube.com"
1269 );
1270 }
1271
1272 #[ntex::test]
1273 async fn test_content_security_policy_sandbox() {
1274 let mw = Pipeline::new(
1275 Helmet::new()
1276 .add(ContentSecurityPolicy::new().sandbox(vec!["allow-forms", "allow-scripts"]))
1277 .create(ok_service()),
1278 );
1279
1280 let req = TestRequest::default().to_srv_request();
1281 let resp = mw.call(req).await.unwrap();
1282 assert_eq!(
1283 resp.headers().get("Content-Security-Policy").unwrap(),
1284 "sandbox allow-forms allow-scripts"
1285 );
1286 }
1287
1288 #[ntex::test]
1289 async fn test_content_security_policy_form_action() {
1290 let mw = Pipeline::new(
1291 Helmet::new()
1292 .add(
1293 ContentSecurityPolicy::new().form_action(vec!["'self'", "https://youtube.com"]),
1294 )
1295 .create(ok_service()),
1296 );
1297
1298 let req = TestRequest::default()
1299 .header("Origin", "https://example.com")
1300 .to_srv_request();
1301 let resp = mw.call(req).await.unwrap();
1302 assert_eq!(
1303 resp.headers().get("Content-Security-Policy").unwrap(),
1304 "form-action 'self' https://youtube.com"
1305 );
1306 }
1307
1308 #[ntex::test]
1309 async fn test_content_security_policy_frame_ancestors() {
1310 let mw = Pipeline::new(
1311 Helmet::new()
1312 .add(
1313 ContentSecurityPolicy::new()
1314 .frame_ancestors(vec!["'self'", "https://youtube.com"]),
1315 )
1316 .create(ok_service()),
1317 );
1318
1319 let req = TestRequest::default()
1320 .header("Origin", "https://example.com")
1321 .to_srv_request();
1322 let resp = mw.call(req).await.unwrap();
1323 assert_eq!(
1324 resp.headers().get("Content-Security-Policy").unwrap(),
1325 "frame-ancestors 'self' https://youtube.com"
1326 );
1327 }
1328
1329 #[ntex::test]
1330 async fn test_content_security_policy_report_to() {
1331 let mw = Pipeline::new(
1332 Helmet::new()
1333 .add(ContentSecurityPolicy::new().report_to(vec!["default", "endpoint", "group"]))
1334 .create(ok_service()),
1335 );
1336
1337 let req = TestRequest::default().to_srv_request();
1338 let resp = mw.call(req).await.unwrap();
1339
1340 assert_eq!(
1341 resp.headers()
1342 .get("Content-Security-Policy")
1343 .unwrap()
1344 .to_str()
1345 .unwrap(),
1346 "report-to default endpoint group; report-uri default endpoint group"
1347 );
1348 }
1349
1350 #[ntex::test]
1351 async fn test_content_security_policy_trusted_types() {
1352 let mw = Pipeline::new(
1353 Helmet::new()
1354 .add(
1355 ContentSecurityPolicy::new()
1356 .trusted_types(vec!["'self'", "https://youtube.com"]),
1357 )
1358 .create(ok_service()),
1359 );
1360
1361 let req = TestRequest::default().to_srv_request();
1362 let resp = mw.call(req).await.unwrap();
1363
1364 assert_eq!(
1365 resp.headers()
1366 .get("Content-Security-Policy")
1367 .unwrap()
1368 .to_str()
1369 .unwrap(),
1370 "trusted-types 'self' https://youtube.com"
1371 );
1372 }
1373
1374 #[ntex::test]
1375 async fn test_content_security_policy_require_trusted_types_for() {
1376 let mw = Pipeline::new(
1377 Helmet::new()
1378 .add(
1379 ContentSecurityPolicy::new().require_trusted_types_for(vec!["script", "style"]),
1380 )
1381 .create(ok_service()),
1382 );
1383
1384 let req = TestRequest::default().to_srv_request();
1385 let resp = mw.call(req).await.unwrap();
1386
1387 assert_eq!(
1388 resp.headers()
1389 .get("Content-Security-Policy")
1390 .unwrap()
1391 .to_str()
1392 .unwrap(),
1393 "require-trusted-types-for script style"
1394 );
1395 }
1396
1397 #[ntex::test]
1398 async fn test_content_security_policy_upgrade_insecure_requests() {
1399 let mw = Pipeline::new(
1400 Helmet::new()
1401 .add(ContentSecurityPolicy::new().upgrade_insecure_requests())
1402 .create(ok_service()),
1403 );
1404
1405 let req = TestRequest::default().to_srv_request();
1406 let resp = mw.call(req).await.unwrap();
1407 assert_eq!(
1408 resp.headers().get("Content-Security-Policy").unwrap(),
1409 "upgrade-insecure-requests"
1410 );
1411 }
1412
1413 #[ntex::test]
1414 async fn test_helmet_default() {
1415 let mw = Pipeline::new(Helmet::default().create(ok_service()));
1416
1417 let req = TestRequest::default().to_srv_request();
1418 let resp = mw.call(req).await.unwrap();
1419
1420 assert_eq!(
1421 resp.headers().get("Content-Security-Policy").unwrap(),
1422 "default-src 'self'; base-uri 'self'; font-src 'self' https: data:; form-action 'self'; frame-ancestors 'self'; img-src 'self' data:; object-src 'none'; script-src 'self'; script-src-attr 'none'; style-src 'self' https: 'unsafe-inline'; upgrade-insecure-requests"
1423 );
1424 assert_eq!(
1425 resp.headers().get("Cross-Origin-Opener-Policy").unwrap(),
1426 "same-origin"
1427 );
1428 assert_eq!(
1429 resp.headers().get("Cross-Origin-Resource-Policy").unwrap(),
1430 "same-origin"
1431 );
1432 assert_eq!(resp.headers().get("Origin-Agent-Cluster").unwrap(), "?1");
1433 assert_eq!(
1434 resp.headers().get("Referrer-Policy").unwrap(),
1435 "no-referrer"
1436 );
1437 assert_eq!(
1438 resp.headers().get("Strict-Transport-Security").unwrap(),
1439 "max-age=15552000; includeSubDomains"
1440 );
1441 assert_eq!(
1442 resp.headers().get("X-Content-Type-Options").unwrap(),
1443 "nosniff"
1444 );
1445 assert_eq!(resp.headers().get("X-DNS-Prefetch-Control").unwrap(), "off");
1446 assert_eq!(resp.headers().get("X-Download-Options").unwrap(), "noopen");
1447 assert_eq!(resp.headers().get("X-Frame-Options").unwrap(), "SAMEORIGIN");
1448 assert_eq!(
1449 resp.headers()
1450 .get("X-Permitted-Cross-Domain-Policies")
1451 .unwrap(),
1452 "none"
1453 );
1454 }
1455
1456 #[ntex::test]
1457 async fn test_content_security_policy_report_only() {
1458 let mw = Pipeline::new(
1459 Helmet::new()
1460 .add(
1461 ContentSecurityPolicy::new()
1462 .report_only()
1463 .base_uri(vec!["'self'"]),
1464 )
1465 .create(ok_service()),
1466 );
1467
1468 let req = TestRequest::default().to_srv_request();
1469 let resp = mw.call(req).await.unwrap();
1470
1471 assert!(resp.headers().get("Content-Security-Policy").is_none());
1472
1473 assert_eq!(
1474 resp.headers()
1475 .get("Content-Security-Policy-Report-Only")
1476 .unwrap()
1477 .to_str()
1478 .unwrap(),
1479 "base-uri 'self'"
1480 );
1481 }
1482}