package main // https://pkg.go.dev/github.com/tebeka/selenium#example-package // https://github.com/domainr/whois // https://golangexample.com/dns-lookup-using-go/ /* chandler@xenon ~/projects/hats-domains % for i in {1..50}; do [21:17:08] dig ${i}hats.com | grep -i nxdomain >/dev/null && echo ${i}hats.com is available done 5hats.com is available 16hats.com is available 26hats.com is available 28hats.com is available 30hats.com is available 35hats.com is available 36hats.com is available 37hats.com is available 41hats.com is available 43hats.com is available 44hats.com is available 46hats.com is available 48hats.com is available 49hats.com is available [1] chandler@xenon ~/projects/hats-domains % */ import ( "encoding/base64" "flag" "fmt" "html/template" "io" "log" "net/http" "os" "time" "github.com/tebeka/selenium" ) type HatsSite struct { DomainName string Owner string Since time.Time ScreenshotURL template.URL Title string FetchTime time.Time HTTPOpen bool HTTPSOpen bool } func getSites(largest int, wd selenium.WebDriver) (sites []HatsSite, err error) { for i := 2; i <= largest; i++ { domainName := fmt.Sprintf("%vhats.com", i) err := wd.Get(fmt.Sprintf("http://%v/", domainName)) if err != nil { return sites, err } title, err := wd.Title() if err != nil { return sites, err } screenshot, err := wd.Screenshot() if err != nil { return sites, err } sites = append(sites, HatsSite{ DomainName: domainName, Owner: "unknown", ScreenshotURL: template.URL(fmt.Sprintf("data:image/png;base64,%v", base64.StdEncoding.EncodeToString(screenshot))), Title: title, FetchTime: time.Now(), HTTPOpen: false, // TODO HTTPSOpen: false, // TODO }) } return sites, nil } func generateHTML(sites []HatsSite, w io.Writer) error { tmpl, err := template.New("main").Parse(` {n}hats.com domains

{n}hats.com domains

{{range .}}

{{.DomainName}}

Fetched
{{.FetchTime.Format "Mon Jan 2 15:04:05 -0700 MST 2006" }}
Title
{{.Title}}
Owner
{{.Owner}}
Since
{{.Since.Format "Mon Jan 2 2006" }}
screenshot of {{.DomainName}} as of {{.FetchTime.Format {{end}} `) if err != nil { return err } return tmpl.Execute(w, sites) } func main() { serve := flag.Bool("serve", false, "Serve HTTP rather than writing a file") filename := flag.String("path", "index.html", "Output filename (if -serve=false, default)") port := flag.Int("port", 8080, "Port to serve on") largest := flag.Int("largest", 50, "largest n for {n}hats.com") flag.Parse() const ( geckoDriverPath = "deps/geckodriver" geckoDriverPort = 8080 ) opts := []selenium.ServiceOption{ selenium.StartFrameBuffer(), selenium.Output(nil), } selenium.SetDebug(true) service, err := selenium.NewGeckoDriverService(geckoDriverPath, geckoDriverPort, opts...) if err != nil { panic(err) } defer service.Stop() wd, err := selenium.NewRemote(nil, fmt.Sprintf("http://localhost:%d", geckoDriverPort)) if err != nil { panic(err) } defer wd.Quit() if *serve { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { // err := generateHTML(w, *largest, wd) // if err != nil { // w.Write([]byte(err.Error())) // } }) fmt.Printf("Serving on %v\n", port) log.Fatal(http.ListenAndServe(fmt.Sprintf(":%v", *port), nil)) } else { file, err := os.Create(*filename) if err != nil { panic(err) } sites, err := getSites(*largest, wd) if err != nil { fmt.Println(err) } err = generateHTML(sites, file) if err != nil { fmt.Println(err) } } }