2021-10-18 17:42:25 -05:00
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 : 0 8 ]
dig $ { i } hats . com | grep - i nxdomain > / dev / null && echo $ { i } hats . com is available
done
5 hats . com is available
16 hats . com is available
26 hats . com is available
28 hats . com is available
30 hats . com is available
35 hats . com is available
36 hats . com is available
37 hats . com is available
41 hats . com is available
43 hats . com is available
44 hats . com is available
46 hats . com is available
48 hats . com is available
49 hats . com is available
[ 1 ] chandler @ xenon ~ / projects / hats - domains %
* /
import (
2021-10-18 19:32:10 -05:00
_ "embed"
2021-10-18 17:56:43 -05:00
"encoding/base64"
2021-10-18 17:42:25 -05:00
"flag"
"fmt"
"html/template"
"io"
"log"
2021-10-18 22:36:35 -05:00
"net"
2021-10-18 17:42:25 -05:00
"net/http"
"os"
"time"
2021-10-18 19:18:32 -05:00
"github.com/likexian/whois"
whoisparser "github.com/likexian/whois-parser"
2021-10-18 17:42:25 -05:00
"github.com/tebeka/selenium"
)
type HatsSite struct {
DomainName string
2021-10-18 19:18:32 -05:00
Available bool
FetchTime time . Time
DomainInfo * whoisparser . Domain
Registrar * whoisparser . Contact
Registrant * whoisparser . Contact
2021-10-18 17:56:43 -05:00
ScreenshotURL template . URL
2021-10-18 17:42:25 -05:00
Title string
2021-10-18 22:36:35 -05:00
Notes template . HTML
2021-10-18 22:48:11 -05:00
Error template . HTML
2021-10-18 17:42:25 -05:00
}
2021-10-18 22:48:11 -05:00
func getSite ( domainName string , wd selenium . WebDriver ) ( hatsSite HatsSite ) {
2021-10-18 23:02:02 -05:00
log . Printf ( "Retrieving info for %v\n" , domainName )
2021-10-18 17:42:25 -05:00
2021-10-18 22:48:11 -05:00
hatsSite . DomainName = domainName
hatsSite . FetchTime = time . Now ( )
2021-10-18 17:42:25 -05:00
2021-10-18 22:48:11 -05:00
// Check if domain is registered
query_result , err := whois . Whois ( hatsSite . DomainName )
if err != nil {
hatsSite . Error = template . HTML ( err . Error ( ) )
return
}
result , err := whoisparser . Parse ( query_result )
if err == whoisparser . ErrNotFoundDomain {
hatsSite . Available = true
hatsSite . Notes = template . HTML ( fmt . Sprintf ( "Register at <a href='https://www.namecheap.com/domains/registration/results/?domain=%v'>NameCheap</a>" , hatsSite . DomainName ) )
return
} else if err != nil {
hatsSite . Error = template . HTML ( err . Error ( ) )
return
}
hatsSite . Available = false
hatsSite . DomainInfo = result . Domain
hatsSite . Registrar = result . Registrar
hatsSite . Registrant = result . Registrant
2021-10-18 22:36:35 -05:00
2021-10-18 22:48:11 -05:00
_ , err = net . LookupHost ( hatsSite . DomainName )
if err != nil {
hatsSite . Notes = template . HTML ( fmt . Sprintf ( "DNS Error: <code>%v</code>" , err . Error ( ) ) )
return
}
2021-10-18 19:18:32 -05:00
2021-10-18 22:48:11 -05:00
// Get web page, take screenshot
err = wd . Get ( fmt . Sprintf ( "http://%v/" , hatsSite . DomainName ) )
if err != nil {
hatsSite . Error = template . HTML ( err . Error ( ) )
return
}
2021-10-18 17:42:25 -05:00
2021-10-18 22:48:11 -05:00
hatsSite . Title , err = wd . Title ( )
if err != nil {
hatsSite . Error = template . HTML ( err . Error ( ) )
return
}
screenshot , err := wd . Screenshot ( )
if err != nil {
hatsSite . Error = template . HTML ( err . Error ( ) )
return
}
hatsSite . ScreenshotURL = template . URL ( fmt . Sprintf ( "data:image/png;base64,%v" , base64 . StdEncoding . EncodeToString ( screenshot ) ) )
return
}
func getSites ( largest int , wd selenium . WebDriver ) ( sites [ ] HatsSite ) {
domains := [ ] string { "0hats.com" , "1hat.com" } // Special cases
//domains = append(domains, "hats.com", "onehat.com", "twohats.com", "nhats.com") // Possibly more special cases?
for i := 2 ; i <= largest ; i ++ {
domains = append ( domains , fmt . Sprintf ( "%dhats.com" , i ) )
}
2021-10-18 17:42:25 -05:00
2021-10-18 22:48:11 -05:00
for _ , domain := range domains {
sites = append ( sites , getSite ( domain , wd ) )
2021-10-18 17:42:25 -05:00
}
2021-10-18 22:48:11 -05:00
return sites
2021-10-18 17:42:25 -05:00
}
2021-10-18 19:32:10 -05:00
//go:embed template.html
var rawtmpl string
2021-10-18 17:42:25 -05:00
func generateHTML ( sites [ ] HatsSite , w io . Writer ) error {
2021-10-18 19:18:32 -05:00
funcs := template . FuncMap {
"parseTime" : func ( s string ) time . Time { time , _ := time . Parse ( time . RFC3339 , s ) ; return time } ,
}
2021-10-18 19:32:10 -05:00
tmpl , err := template . New ( "main" ) . Funcs ( funcs ) . Parse ( rawtmpl )
2021-10-18 17:42:25 -05:00
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" )
2021-10-18 18:55:36 -05:00
debug := flag . Bool ( "debug" , false , "Enable debug logging for the selenium package" )
2021-10-18 17:42:25 -05:00
largest := flag . Int ( "largest" , 50 , "largest n for {n}hats.com" )
flag . Parse ( )
const (
geckoDriverPath = "deps/geckodriver"
2021-10-19 00:36:02 -05:00
geckoDriverPort = 8081
2021-10-18 17:42:25 -05:00
)
2021-10-18 17:43:46 -05:00
2021-10-18 17:42:25 -05:00
opts := [ ] selenium . ServiceOption {
2021-10-18 17:43:46 -05:00
selenium . StartFrameBuffer ( ) ,
2021-10-18 17:42:25 -05:00
selenium . Output ( nil ) ,
}
2021-10-18 18:55:36 -05:00
selenium . SetDebug ( * debug )
2021-10-18 17:43:46 -05:00
service , err := selenium . NewGeckoDriverService ( geckoDriverPath , geckoDriverPort , opts ... )
2021-10-18 17:42:25 -05:00
if err != nil {
2021-10-18 17:43:46 -05:00
panic ( err )
2021-10-18 17:42:25 -05:00
}
defer service . Stop ( )
2021-10-18 17:43:46 -05:00
2022-04-02 00:25:20 -05:00
wd , err := selenium . NewRemote ( selenium . Capabilities {
"acceptInsecureCerts" : true ,
} , fmt . Sprintf ( "http://localhost:%d" , geckoDriverPort ) )
2021-10-18 17:42:25 -05:00
if err != nil {
panic ( err )
}
defer wd . Quit ( )
if * serve {
http . HandleFunc ( "/" , func ( w http . ResponseWriter , r * http . Request ) {
2021-10-19 00:36:02 -05:00
err = generateHTML ( getSites ( * largest , wd ) , w )
if err != nil {
w . Write ( [ ] byte ( err . Error ( ) ) )
}
2021-10-18 17:42:25 -05:00
} )
2021-10-19 00:36:02 -05:00
fmt . Printf ( "Serving on %v\n" , * port )
2021-10-18 17:42:25 -05:00
log . Fatal ( http . ListenAndServe ( fmt . Sprintf ( ":%v" , * port ) , nil ) )
} else {
file , err := os . Create ( * filename )
if err != nil {
panic ( err )
}
2021-10-18 22:48:11 -05:00
err = generateHTML ( getSites ( * largest , wd ) , file )
2021-10-18 17:42:25 -05:00
if err != nil {
2021-10-18 23:31:17 -05:00
log . Fatal ( err )
2021-10-18 17:42:25 -05:00
}
}
}