From 8ff42709010e8d46914000f64181c445aa5dea34 Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Sat, 15 Aug 2020 05:36:17 -0600 Subject: [PATCH] add hashcash cli --- .gitignore | 2 + README.md | 34 +++++++++ cmd/hashcash/hashcash.go | 144 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 180 insertions(+) create mode 100644 cmd/hashcash/hashcash.go diff --git a/.gitignore b/.gitignore index f4d432a..fdf0efe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +cmd/hashcash/hashcash + # ---> Go # Binaries for programs and plugins *.exe diff --git a/README.md b/README.md index 8d9943c..38cdf4c 100644 --- a/README.md +++ b/README.md @@ -5,3 +5,37 @@ HTTP Hashcash implemented in Go. Explanation at https://therootcompany.com/blog/http-hashcash/ Go docs at https://godoc.org/git.rootprojects.org/root/hashcash + +# CLI Usage + +Install: + +```bash +go get git.rootprojects.org/root/hashcash/cmd/hashcash +``` + +Usage: + +```txt +Usage: + hashcash new [subject *] [expires in 5m] [difficulty 10] + hashcash parse + hashcash solve + hashcash verify [subject *] +``` + +Example: + +```bash +my_hc=$(hashcash new) +echo New: $my_hc +hashcash parse "$my_hc" +echo "" + +my_hc=$(hashcash solve "$my_hc") +echo Solved: $my_hc +hashcash parse "$my_hc" +echo "" + +hashcash verify "$my_hc" +``` diff --git a/cmd/hashcash/hashcash.go b/cmd/hashcash/hashcash.go new file mode 100644 index 0000000..f5c5460 --- /dev/null +++ b/cmd/hashcash/hashcash.go @@ -0,0 +1,144 @@ +package main + +import ( + "encoding/json" + "fmt" + "os" + "strconv" + "time" + + "git.rootprojects.org/root/hashcash" +) + +func help() { + fmt.Println("Usage:") + fmt.Println("\thashcash new [subject *] [expires in 5m] [difficulty 10]") + fmt.Println("\thashcash parse ") + fmt.Println("\thashcash solve ") + fmt.Println("\thashcash verify [subject *]") +} + +func main() { + args := os.Args[:] + + if len(args) < 2 { + help() + os.Exit(1) + return + } + + switch args[1] { + case "new": + var subject string + if len(args) > 3 { + subject = args[2] + } + + var difficulty int + if len(args) > 4 { + var err error + difficulty, err = strconv.Atoi(args[3]) + if nil != err { + help() + os.Exit(1) + } + } + + var expIn time.Duration + if len(args) > 5 { + var err error + expIn, err = time.ParseDuration(args[4]) + if nil != err { + help() + os.Exit(1) + } + } else { + expIn = 5 * time.Minute + } + + h := hashcash.New(hashcash.Hashcash{ + Subject: subject, + Difficulty: difficulty, + ExpiresAt: time.Now().Add(expIn), + }) + + fmt.Println(h.String()) + return + case "parse": + var token string + if 3 != len(args) { + help() + os.Exit(1) + return + } + token = args[2] + h, err := hashcash.Parse(token) + if nil != err { + fmt.Fprintf(os.Stderr, "%s\n", err) + return + } + b, _ := json.MarshalIndent(h, "", " ") + fmt.Println(string(b)) + return + case "solve": + var token string + if 3 != len(args) { + help() + os.Exit(1) + return + } + token = args[2] + h, err := hashcash.Parse(token) + if nil != err { + fmt.Fprintf(os.Stderr, "%s\n", err) + os.Exit(1) + return + } + err = h.Solve(22) + if nil != err { + fmt.Fprintf(os.Stderr, "%s\n", err) + os.Exit(1) + return + } + + fmt.Println(h.String()) + return + case "verify": + var token string + if len(args) < 3 { + help() + os.Exit(1) + return + } + token = args[2] + h, err := hashcash.Parse(token) + if nil != err { + fmt.Fprintf(os.Stderr, "%s\n", err) + return + } + + subject := "*" + if len(args) > 3 { + subject = args[3] + } + + err = h.Verify(subject) + if nil != err { + fmt.Fprintf(os.Stderr, "%s\n", err) + return + } + + var duration string + dur := h.ExpiresAt.Sub(time.Now()) + if dur > 365*24*time.Hour { + duration = "...a long, long time" + } else { + duration = dur.Truncate(time.Second).String() + } + fmt.Println("valid for", duration) + return + default: + help() + os.Exit(1) + } +}