@@ -2,14 +2,12 @@ package main
2
2
3
3
import (
4
4
"fmt"
5
- "net"
6
5
"net/url"
7
6
"os"
8
- "os/exec"
9
7
"strings"
10
8
"text/tabwriter"
11
9
12
- "golang.org/x/net/publicsuffix "
10
+ "github.com/bradleyjkemp/abwhose/matchers "
13
11
)
14
12
15
13
func main () {
@@ -23,101 +21,83 @@ func main() {
23
21
}
24
22
}
25
23
26
- var tabWriter = tabwriter .NewWriter (os .Stdout , 12 , 2 , 1 , ' ' , tabwriter .TabIndent )
27
-
28
- func run (abuseURL string ) error {
29
- var abusive * url.URL
30
- var err error
31
- if strings .Contains (abuseURL , "/" ) {
32
- // This looks like a full URL instead of a plain domain
33
- if ! strings .HasPrefix (abuseURL , "http://" ) && ! strings .HasPrefix (abuseURL , "https://" ) {
34
- // Doesn't have a protocol so won't url.Parse properly
35
- abuseURL = "http://" + abuseURL
36
- }
37
-
38
- abusive , err = url .Parse (abuseURL )
39
- if err != nil {
40
- return fmt .Errorf ("couldn't parse URL: %w" , err )
41
- }
42
- } else {
43
- // This is a plain domain name so we construct a URL directly
44
- abusive = & url.URL {
45
- Scheme : "http" ,
46
- Host : abuseURL ,
47
- }
48
- }
49
-
50
- if abusive .Hostname () == "" {
51
- return fmt .Errorf ("%s doesn't look like a valid URL (hostname is empty)" , abuseURL )
24
+ func run (query string ) error {
25
+ u , err := parseURL (query )
26
+ if err != nil {
27
+ return err
52
28
}
53
29
54
- // First look up abuse details for the domain itself (this will be the registrar)
55
- rootDomain , _ := publicsuffix .EffectiveTLDPlusOne (abusive .Hostname ())
56
-
57
- // First check if this is a shared host
58
- var sharedHost bool
59
- for _ , matcher := range sharedHostMatchers {
60
- if match , display := matcher (rootDomain ); match {
61
- if ! sharedHost {
62
- fmt .Println ("Report abuse to shared hosting provider:" )
63
- }
64
- display ()
65
- sharedHost = true
66
- }
67
- }
68
- // If this is a shared host then skip the WHOIS lookup
69
- // as that information isn't useful.
70
- if sharedHost {
30
+ if ok , contact := matchers .IsSharedHostingProvider (u ); ok {
31
+ fmt .Println ("Report abuse to shared hosting provider:" )
32
+ printContactDetails (u , contact )
33
+ // If this is a shared host then skip the rest of the lookups
34
+ // as that information isn't useful.
71
35
return nil
72
36
}
73
37
74
- err = getAbuseReportDetails ( "Report abuse to domain registrar:" , abusive , rootDomain )
38
+ contacts , err := matchers . Registrar ( u )
75
39
if err != nil {
76
- return fmt .Errorf ("failed to get registrar abuse details: %w" , err )
77
- }
78
-
79
- // Now look up the IP in order to find the hosting provider
80
- ips , err := net .LookupIP (abusive .Hostname ())
81
- if err != nil {
82
- return fmt .Errorf ("failed to find hosting provider: %w" , err )
40
+ return err
83
41
}
42
+ fmt .Println ("Report abuse to domain registrar:" )
43
+ printContactDetails (u , contacts ... )
84
44
85
- // Abuse details for the IP should be the hosting provider
86
- err = getAbuseReportDetails ("Report abuse to host:" , abusive , ips [0 ].String ())
45
+ contacts , err = matchers .HostingProvider (u )
87
46
if err != nil {
88
- return fmt . Errorf ( "failed to get host abuse details: %w" , err )
47
+ return err
89
48
}
49
+ fmt .Println ("Report abuse to hosting provider:" )
50
+ printContactDetails (u , contacts ... )
90
51
return nil
91
52
}
92
53
93
- func getAbuseReportDetails (header string , abusive * url.URL , query string ) error {
94
- rawWhois , err := exec .Command ("whois" , query ).CombinedOutput ()
54
+ func parseURL (input string ) (* url.URL , error ) {
55
+ if ! strings .Contains (input , "/" ) {
56
+ // This is likely a plain domain name so we construct a URL directly
57
+ return & url.URL {
58
+ Scheme : "http" ,
59
+ Host : input ,
60
+ }, nil
61
+ }
62
+
63
+ // This looks like a full URL instead of a plain domain
64
+ if ! strings .HasPrefix (input , "http://" ) && ! strings .HasPrefix (input , "https://" ) {
65
+ // Doesn't have a protocol so won't url.Parse properly
66
+ input = "http://" + input
67
+ }
68
+
69
+ u , err := url .Parse (input )
95
70
if err != nil {
96
- return err
71
+ return nil , fmt .Errorf ("couldn't parse URL: %w" , err )
72
+ }
73
+ if u .Hostname () == "" {
74
+ return nil , fmt .Errorf ("%s doesn't look like a valid URL (hostname is empty)" , input )
97
75
}
98
76
99
- gotMatch := false
100
- for _ , matcher := range whoisMatchers {
101
- if match , display := matcher (string (rawWhois )); match {
102
- if ! gotMatch {
103
- fmt .Println (header )
104
- gotMatch = true
77
+ return u , nil
78
+ }
79
+
80
+ var tabWriter = tabwriter .NewWriter (os .Stdout , 12 , 2 , 1 , ' ' , tabwriter .TabIndent )
81
+
82
+ func printContactDetails (u * url.URL , contacts ... matchers.ProviderContact ) {
83
+ for _ , contact := range contacts {
84
+ switch c := contact .(type ) {
85
+ case matchers.AbuseEmail :
86
+ if emailTemplateConfigured () {
87
+ offerToSendEmail (u , c )
88
+ } else {
89
+ fmt .Fprintf (tabWriter , " Email:\t %s\n " , c .Email )
105
90
}
106
- display ()
91
+
92
+ case matchers.OnlineForm :
93
+ fmt .Fprintf (tabWriter , " %s:\t Fill out abuse form %s\n " , contact .Name (), c .URL )
94
+
95
+ default :
96
+ panic (fmt .Sprintf ("unknown contact type: %T" , contact ))
107
97
}
108
98
}
109
- if gotMatch {
110
- return nil
99
+ if len ( contacts ) == 0 {
100
+ fmt . Fprintf ( tabWriter , " Couldn't find any contact details \n " )
111
101
}
112
-
113
- // None of the specific matchers hit so use a generic one
114
- found , display := fallbackEmailMatcher (header , abusive , string (rawWhois ))
115
- if found {
116
- display ()
117
- return nil
118
- }
119
-
120
- fmt .Println (header )
121
- fmt .Println (" couldn't find any abuse contact details" )
122
- return nil
102
+ tabWriter .Flush ()
123
103
}
0 commit comments