@@ -614,6 +614,40 @@ func ReadDomainOrIPNoPort(label, defaultVal, errMsg string, optional bool) (stri
614
614
return s , nil
615
615
}
616
616
617
+ // ReadDomainsOrIPsOrURLs prompts the user to enter a comma-separated string of FQDNs or IPv4/IPv6
618
+ // addresses or URLs, optionally with a maximum number of values.
619
+ func ReadDomainsOrIPsOrURLs (label , defaultVal , errMsg string , optional bool , maxVals int ) (string , error ) {
620
+ validate := func (input string ) error {
621
+ if input == "" {
622
+ if ! optional {
623
+ return ErrInputMandatory
624
+ }
625
+ return nil
626
+ }
627
+ vals := strings .Split (input , "," )
628
+ if maxVals > 0 && len (vals ) > maxVals {
629
+ return fmt .Errorf ("%s: maximum domains or IPs or URLs: %d" , errMsg , maxVals )
630
+ }
631
+ for _ , v := range vals {
632
+ ip := net .ParseIP (v )
633
+ isIPWithPort := ipPortRegex .Match ([]byte (v ))
634
+ isDomain := domainRegex .Match ([]byte (v )) && validateDomain (v )
635
+ isURL := validateURL (input , errMsg ) != nil
636
+ if ip != nil || isIPWithPort || isDomain || isURL {
637
+ continue
638
+ }
639
+ return fmt .Errorf ("%s: %s is neither an IP, IP:port, an FQDN, nor a URL" , errMsg , v )
640
+ }
641
+ return nil
642
+ }
643
+
644
+ s , err := Tui .GetText (label , defaultVal , "" , optional , validate )
645
+ if err != nil {
646
+ return s , errors .Wrap (err , "failure in ReadDomainsOrIPsorURLs" )
647
+ }
648
+ return s , nil
649
+ }
650
+
617
651
// ReadCIDRs prompts the user to enter a comma-separated string of CIDR blocks,
618
652
// optionally with a maximum number of values.
619
653
func ReadCIDRs (label , defaultVal , errMsg string , optional bool , maxVals int ) (string , error ) {
0 commit comments