@@ -9,6 +9,7 @@ use sha3::Digest;
99
1010use crate :: {
1111 DbConnLike ,
12+ context:: AppContext ,
1213 error:: AppError ,
1314 models:: {
1415 monitor:: MonitorId ,
@@ -46,7 +47,7 @@ pub struct TimeSource {
4647#[ derive( Debug , Deserialize , Clone , PartialEq , Eq ) ]
4748pub struct NewTimeSource {
4849 pub hostname : String ,
49- pub port : Option < Port > ,
50+ pub port : Port ,
5051}
5152
5253#[ derive( Debug , Deserialize , Clone ) ]
@@ -60,39 +61,47 @@ pub struct UpdateTimeSourceForm {
6061 pub weight : i32 ,
6162}
6263
63- impl TryFrom < NewTimeSourceForm > for NewTimeSource {
64- type Error = AppError ;
64+ const DEFAULT_NTSKE_PORT : u16 = 4460 ;
6565
66- fn try_from ( form : NewTimeSourceForm ) -> Result < Self , Self :: Error > {
67- let port = if form. port . is_empty ( ) {
68- None
66+ impl NewTimeSourceForm {
67+ pub fn into_new_source ( self , context : & AppContext ) -> Result < NewTimeSource , AppError > {
68+ let port = if self . port . is_empty ( ) {
69+ DEFAULT_NTSKE_PORT
70+ . try_into ( )
71+ . wrap_err ( "Internal app error, 4460 not a valid port" ) ?
6972 } else {
70- Some (
71- form. port
72- . parse :: < u16 > ( )
73- . wrap_err ( "Could not parse into port number" ) ?
74- . try_into ( )
75- . wrap_err ( "Could not parse into port number" ) ?,
76- )
73+ self . port
74+ . parse :: < u16 > ( )
75+ . wrap_err ( "Could not parse into port number" ) ?
76+ . try_into ( )
77+ . wrap_err ( "Could not parse into port number" ) ?
7778 } ;
7879
79- // Check domain name is reasonable (cf. RFC 1035)
80- if form. hostname . is_empty ( )
81- || !form
82- . hostname
83- . chars ( )
84- . all ( |c| matches ! ( c, '0' ..='9' | '.' | '-' | 'a' ..='z' | 'A' ..='Z' ) )
85- {
86- return Err ( eyre:: eyre!( "Invalid domain name" ) . into ( ) ) ;
87- }
80+ check_hostname_reasonable ( & self . hostname , context) ?;
8881
89- Ok ( Self {
90- hostname : form . hostname ,
82+ Ok ( NewTimeSource {
83+ hostname : self . hostname ,
9184 port,
9285 } )
9386 }
9487}
9588
89+ fn check_hostname_reasonable ( hostname : & str , context : & AppContext ) -> Result < ( ) , AppError > {
90+ if hostname. is_empty ( )
91+ || !hostname
92+ . chars ( )
93+ . all ( |c| matches ! ( c, '0' ..='9' | '.' | '-' | 'a' ..='z' | 'A' ..='Z' ) )
94+ || hostname. ends_with ( ".local" )
95+ || hostname. ends_with ( "." )
96+ || hostname. ends_with ( "localhost" )
97+ || hostname. ends_with ( & context. ke_domain )
98+ {
99+ return Err ( eyre:: eyre!( "Invalid domain name" ) . into ( ) ) ;
100+ }
101+
102+ Ok ( ( ) )
103+ }
104+
96105pub async fn infer_regions (
97106 hostname : impl AsRef < str > ,
98107 geodb : & maxminddb:: Reader < impl AsRef < [ u8 ] > > ,
@@ -466,131 +475,208 @@ mod tests {
466475 #[ test]
467476 fn test_time_source_form_valid_without_port_1 ( ) {
468477 assert_eq ! (
469- NewTimeSource :: try_from ( NewTimeSourceForm {
478+ NewTimeSourceForm {
470479 hostname: "test" . into( ) ,
471480 port: "" . into( )
472- } )
481+ }
482+ . into_new_source( & AppContext :: default ( ) )
473483 . unwrap( ) ,
474484 NewTimeSource {
475485 hostname: "test" . into( ) ,
476- port: None
486+ port: 4460 . try_into ( ) . unwrap ( )
477487 }
478488 ) ;
479489 }
480490
481491 #[ test]
482492 fn test_time_source_form_valid_without_port_2 ( ) {
483493 assert_eq ! (
484- NewTimeSource :: try_from ( NewTimeSourceForm {
494+ NewTimeSourceForm {
485495 hostname: "ExAmPlE.com" . into( ) ,
486496 port: "" . into( )
487- } )
497+ }
498+ . into_new_source( & AppContext :: default ( ) )
488499 . unwrap( ) ,
489500 NewTimeSource {
490501 hostname: "ExAmPlE.com" . into( ) ,
491- port: None
502+ port: 4460 . try_into ( ) . unwrap ( ) ,
492503 }
493504 ) ;
494505 }
495506
496507 #[ test]
497508 fn test_time_source_form_valid_with_port ( ) {
498509 assert_eq ! (
499- NewTimeSource :: try_from ( NewTimeSourceForm {
510+ NewTimeSourceForm {
500511 hostname: "test" . into( ) ,
501512 port: "456" . into( )
502- } )
513+ }
514+ . into_new_source( & AppContext :: default ( ) )
503515 . unwrap( ) ,
504516 NewTimeSource {
505517 hostname: "test" . into( ) ,
506- port: Some ( 456 . try_into( ) . unwrap( ) )
518+ port: 456 . try_into( ) . unwrap( )
507519 }
508520 ) ;
509521 }
510522
511523 #[ test]
512524 fn test_time_source_form_reject_weird_characters_1 ( ) {
513525 assert ! (
514- NewTimeSource :: try_from ( NewTimeSourceForm {
526+ NewTimeSourceForm {
515527 hostname: "js(.com" . into( ) ,
516528 port: "" . into( ) ,
517- } )
529+ }
530+ . into_new_source( & AppContext :: default ( ) )
518531 . is_err( )
519532 ) ;
520533 }
521534
522535 #[ test]
523536 fn test_time_source_form_reject_weird_characters_2 ( ) {
524537 assert ! (
525- NewTimeSource :: try_from ( NewTimeSourceForm {
538+ NewTimeSourceForm {
526539 hostname: "jsê.com" . into( ) ,
527540 port: "" . into( ) ,
528- } )
541+ }
542+ . into_new_source( & AppContext :: default ( ) )
529543 . is_err( )
530544 ) ;
531545 }
532546
533547 #[ test]
534548 fn test_time_source_form_reject_weird_characters_3 ( ) {
535549 assert ! (
536- NewTimeSource :: try_from ( NewTimeSourceForm {
550+ NewTimeSourceForm {
537551 hostname
: "[email protected] " . into
( ) , 538552 port: "" . into( ) ,
539- } )
553+ }
554+ . into_new_source( & AppContext :: default ( ) )
540555 . is_err( )
541556 ) ;
542557 }
543558
544559 #[ test]
545560 fn test_time_source_form_reject_port_0 ( ) {
546561 assert ! (
547- NewTimeSource :: try_from ( NewTimeSourceForm {
562+ NewTimeSourceForm {
548563 hostname: "example.com" . into( ) ,
549564 port: "0" . into( ) ,
550- } )
565+ }
566+ . into_new_source( & AppContext :: default ( ) )
551567 . is_err( )
552568 ) ;
553569 }
554570
555571 #[ test]
556572 fn test_time_source_form_reject_port_100000 ( ) {
557573 assert ! (
558- NewTimeSource :: try_from ( NewTimeSourceForm {
574+ NewTimeSourceForm {
559575 hostname: "example.com" . into( ) ,
560576 port: "100000" . into( ) ,
561- } )
577+ }
578+ . into_new_source( & AppContext :: default ( ) )
562579 . is_err( )
563580 ) ;
564581 }
565582
566583 #[ test]
567584 fn test_time_source_form_reject_non_numeric_port ( ) {
568585 assert ! (
569- NewTimeSource :: try_from ( NewTimeSourceForm {
586+ NewTimeSourceForm {
570587 hostname: "example.com" . into( ) ,
571588 port: "fe" . into( ) ,
572- } )
589+ }
590+ . into_new_source( & AppContext :: default ( ) )
573591 . is_err( )
574592 ) ;
575593 }
576594
577595 #[ test]
578596 fn test_time_source_form_reject_port_with_trailing_garbage ( ) {
579597 assert ! (
580- NewTimeSource :: try_from ( NewTimeSourceForm {
598+ NewTimeSourceForm {
581599 hostname: "example.com" . into( ) ,
582600 port: "123 abc" . into( ) ,
583- } )
601+ }
602+ . into_new_source( & AppContext :: default ( ) )
584603 . is_err( )
585604 ) ;
586605 }
587606
588607 #[ test]
589608 fn test_time_source_form_require_hostname ( ) {
590609 assert ! (
591- NewTimeSource :: try_from ( NewTimeSourceForm {
610+ NewTimeSourceForm {
592611 hostname: "" . into( ) ,
593612 port: "" . into( ) ,
613+ }
614+ . into_new_source( & AppContext :: default ( ) )
615+ . is_err( )
616+ ) ;
617+ }
618+
619+ #[ test]
620+ fn test_time_source_form_reject_local ( ) {
621+ assert ! (
622+ NewTimeSourceForm {
623+ hostname: "example.local" . into( ) ,
624+ port: "123" . into( ) ,
625+ }
626+ . into_new_source( & AppContext :: default ( ) )
627+ . is_err( )
628+ ) ;
629+
630+ assert ! (
631+ NewTimeSourceForm {
632+ hostname: "localhost" . into( ) ,
633+ port: "123" . into( ) ,
634+ }
635+ . into_new_source( & AppContext :: default ( ) )
636+ . is_err( )
637+ ) ;
638+
639+ assert ! (
640+ NewTimeSourceForm {
641+ hostname: "example.local." . into( ) ,
642+ port: "123" . into( ) ,
643+ }
644+ . into_new_source( & AppContext :: default ( ) )
645+ . is_err( )
646+ ) ;
647+
648+ assert ! (
649+ NewTimeSourceForm {
650+ hostname: "example.localhost" . into( ) ,
651+ port: "123" . into( ) ,
652+ }
653+ . into_new_source( & AppContext :: default ( ) )
654+ . is_err( )
655+ ) ;
656+ }
657+
658+ #[ test]
659+ fn test_time_source_form_reject_ke_domain ( ) {
660+ assert ! (
661+ NewTimeSourceForm {
662+ hostname: "ke.example.org" . into( ) ,
663+ port: "123" . into( ) ,
664+ }
665+ . into_new_source( & AppContext {
666+ ke_domain: "ke.example.org" . into( ) ,
667+ ..AppContext :: default ( )
668+ } )
669+ . is_err( )
670+ ) ;
671+
672+ assert ! (
673+ NewTimeSourceForm {
674+ hostname: "bla.ke.example.org" . into( ) ,
675+ port: "123" . into( ) ,
676+ }
677+ . into_new_source( & AppContext {
678+ ke_domain: "ke.example.org" . into( ) ,
679+ ..AppContext :: default ( )
594680 } )
595681 . is_err( )
596682 ) ;
0 commit comments