-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit cd2f34d
Showing
9 changed files
with
411 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
infile.txt | ||
build |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
build: | ||
go build -o ./build/namegrind ./cmd/main.go | ||
|
||
test: | ||
go test ./... --race | ||
|
||
.PHONY: build test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# namegrind | ||
|
||
This utility returns sunrise and availability data for [Handshake](https://handshake.org) names. | ||
|
||
## Installation | ||
|
||
1. Download the binary for your OS. | ||
2. Move it somewhere on your `$PATH`, like this: `sude mv namegrind-darwin-x64 /usr/local/bin/namegrind`. You can replace `namegrind-darwin-x64` with the filename and location of the binary you downloaded. | ||
|
||
## Usage | ||
|
||
First, create an input file. The input file is simply a newline-delimited list of names, like this: | ||
|
||
``` | ||
name1. | ||
name2. | ||
name3. | ||
``` | ||
|
||
Then, run `namegrind <infile>`, where `<infile>` is replaced with the location of the input file you created above. | ||
|
||
You'll see output that looks like this: | ||
|
||
``` | ||
honk,15120,13,false | ||
beep,17136,15,false | ||
test,6048,4,false | ||
farb,38304,36,false | ||
1and1,49392,47,true | ||
facebook,32256,30,true | ||
``` | ||
|
||
These fields correspond to `<name>,<available height>,<available week>,<reserved>`. The output can be redirected to a CSV file for easy import into other programs. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package main | ||
|
||
import ( | ||
"bufio" | ||
"encoding/hex" | ||
"fmt" | ||
"github.com/kyokan/namegrind" | ||
"os" | ||
"strings" | ||
) | ||
|
||
func main() { | ||
if len(os.Args) == 0 { | ||
fmt.Println("Usage: namegrind <infile>") | ||
os.Exit(1) | ||
} | ||
|
||
reservationsExist, err := namegrind.ReservationsExist() | ||
if err != nil { | ||
printErr(err) | ||
} | ||
if !reservationsExist { | ||
if err := namegrind.FetchReservations(); err != nil { | ||
printErr(err) | ||
} | ||
} | ||
|
||
reservations, err := namegrind.ParseReservations() | ||
if err != nil { | ||
printErr(err) | ||
} | ||
|
||
inFile := strings.TrimSpace(os.Args[1]) | ||
f, err := os.Open(inFile) | ||
defer f.Close() | ||
scan := bufio.NewScanner(f) | ||
for scan.Scan() { | ||
name := scan.Text() | ||
nameHash, err := namegrind.HashName(name) | ||
if err != nil { | ||
printErr(err) | ||
} | ||
isReserved := reservations[hex.EncodeToString(nameHash)] | ||
week, height := namegrind.Rollout(nameHash) | ||
fmt.Printf("%s,%d,%d,%t\n", name, week, height, isReserved) | ||
} | ||
} | ||
|
||
func printErr(err error) { | ||
_, _ = fmt.Fprintf(os.Stderr, "Error: %v\n", err) | ||
os.Exit(1) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
module github.com/kyokan/namegrind | ||
|
||
go 1.13 | ||
|
||
require ( | ||
github.com/cheggaaa/pb/v3 v3.0.4 | ||
github.com/mitchellh/go-homedir v1.1.0 | ||
github.com/stretchr/testify v1.4.0 | ||
golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72 | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM= | ||
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA= | ||
github.com/cheggaaa/pb v2.0.7+incompatible h1:gLKifR1UkZ/kLkda5gC0K6c8g+jU2sINPtBeOiNlMhU= | ||
github.com/cheggaaa/pb/v3 v3.0.4 h1:QZEPYOj2ix6d5oEg63fbHmpolrnNiwjUsk+h74Yt4bM= | ||
github.com/cheggaaa/pb/v3 v3.0.4/go.mod h1:7rgWxLrAUcFMkvJuv09+DYi7mMUYi8nO9iOWcvGJPfw= | ||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= | ||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= | ||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= | ||
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= | ||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= | ||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= | ||
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10= | ||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= | ||
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54= | ||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= | ||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= | ||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= | ||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= | ||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= | ||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= | ||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||
golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72 h1:+ELyKg6m8UBf0nPFSqD0mi7zUfwPyXo23HNjMnXPz7w= | ||
golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | ||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= | ||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9 h1:ZBzSG/7F4eNKz2L3GE9o300RX0Az1Bw5HF7PDraD+qU= | ||
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= | ||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package namegrind | ||
|
||
import ( | ||
"bufio" | ||
"github.com/cheggaaa/pb/v3" | ||
"github.com/mitchellh/go-homedir" | ||
"io" | ||
"net/http" | ||
"os" | ||
"path" | ||
) | ||
|
||
const ReservationsURL = "https://gist.githubusercontent.com/mslipper/d1a9989a8a175272f51da5e2f43e8d15/raw/72b07b1e29f08575d2feebef21c9da09c5e167cc/namehashes" | ||
|
||
func ReservationsPath() string { | ||
dir, err := homedir.Dir() | ||
if err != nil { | ||
panic(err) | ||
} | ||
return path.Join(dir, "reservations.json") | ||
} | ||
|
||
func ReservationsExist() (bool, error) { | ||
_, err := os.Stat(ReservationsPath()) | ||
if os.IsNotExist(err) { | ||
return false, nil | ||
} | ||
if err != nil { | ||
return false, err | ||
} | ||
return true, nil | ||
} | ||
|
||
func FetchReservations() error { | ||
out, err := os.Create(ReservationsPath()) | ||
defer out.Close() | ||
res, err := http.Get(ReservationsURL) | ||
if err != nil { | ||
return err | ||
} | ||
defer res.Body.Close() | ||
|
||
bar := pb.Full.Start64(res.ContentLength) | ||
if _, err := io.Copy(out, bar.NewProxyReader(res.Body)); err != nil { | ||
return err | ||
} | ||
bar.Finish() | ||
return nil | ||
} | ||
|
||
func ParseReservations() (map[string]bool, error) { | ||
out := make(map[string]bool) | ||
f, err := os.Open(ReservationsPath()) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer f.Close() | ||
|
||
scan := bufio.NewScanner(f) | ||
for scan.Scan() { | ||
line := scan.Text() | ||
out[line] = true | ||
} | ||
|
||
return out, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package namegrind | ||
|
||
import ( | ||
"errors" | ||
"golang.org/x/crypto/sha3" | ||
) | ||
|
||
const ( | ||
MaxNameLen = 64 | ||
MainnetRolloutInterval = 1008 | ||
MainnetAuctionStart = 2016 | ||
) | ||
|
||
var validCharset = []byte{ | ||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, | ||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, | ||
0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | ||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 4, | ||
0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, | ||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, | ||
} | ||
|
||
func ValidateName(name string) error { | ||
if len(name) == 0 { | ||
return errors.New("name must have nonzero length") | ||
} | ||
|
||
if len(name) > MaxNameLen { | ||
return errors.New("name over maximum length") | ||
} | ||
|
||
for i := 0; i < len(name); i++ { | ||
ch := name[i] | ||
|
||
if int(ch) > len(validCharset) { | ||
return errors.New("invalid character") | ||
} | ||
|
||
charType := validCharset[ch] | ||
switch charType { | ||
case 0: | ||
return errors.New("invalid character") | ||
case 1: | ||
continue | ||
case 2: | ||
return errors.New("name cannot contain capital letters") | ||
case 3: | ||
continue | ||
case 4: | ||
if i == 0 { | ||
return errors.New("name cannot start with a hyphen") | ||
} | ||
if i == len(name)-1 { | ||
return errors.New("name cannot end with a hyphen") | ||
} | ||
if name[i-1] == ch { | ||
return errors.New("name cannot contain consecutive hyphens") | ||
} | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func HashName(name string) ([]byte, error) { | ||
if err := ValidateName(name); err != nil { | ||
return nil, err | ||
} | ||
h := sha3.Sum256([]byte(name)) | ||
return h[:], nil | ||
} | ||
|
||
func Rollout(nameHash []byte) (int, int) { | ||
week := modBuffer(nameHash, 52) | ||
height := week * MainnetRolloutInterval | ||
return MainnetAuctionStart + height, week | ||
} | ||
|
||
func modBuffer(buf []byte, num int) int { | ||
if (num & 0xff) != num { | ||
panic("invalid num") | ||
} | ||
if num == 0 { | ||
panic("invalid num") | ||
} | ||
|
||
p := 256 % num | ||
var acc int | ||
for i := 0; i < len(buf); i++ { | ||
acc = (p*acc + int(buf[i])) % num | ||
} | ||
|
||
return acc | ||
} |
Oops, something went wrong.