aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Burwell <ben@benburwell.com>2019-09-09 09:28:43 -0400
committerBen Burwell <ben@benburwell.com>2019-09-09 09:28:43 -0400
commit81342fc5250e14a53b42cb168f7fd6fffad50de5 (patch)
tree19401ed80d2c2ad943eabf67bc549731ddf4d3b1
initial commit
-rw-r--r--.gitignore1
-rw-r--r--go.mod5
-rw-r--r--go.sum9
-rw-r--r--main.go96
4 files changed, 111 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..fbfcc9f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+gosumdbaudit
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..8b85e55
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,5 @@
+module git.sr.ht/~benburwell/gosumdbaudit
+
+go 1.13
+
+require golang.org/x/mod v0.1.0
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..3bd38bf
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,9 @@
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 h1:iMGN4xG0cnqj3t+zOM8wUB0BiPKHEwSxEZCvzcbZuvk=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/mod v0.1.0 h1:sfUMP1Gu8qASkorDVjnMuvgJzwFbTZSeXFiGBYAVdl4=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..d08cdbd
--- /dev/null
+++ b/main.go
@@ -0,0 +1,96 @@
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "log"
+ "net/http"
+ "strconv"
+ "strings"
+
+ "golang.org/x/mod/sumdb/note"
+)
+
+func main() {
+ dbs := []*db{
+ &db{host: "sum.golang.org", key: "sum.golang.org+033de0ae+Ac4zctda0e5eza+HJyk9SxEdh+s3Ux18htTTAD8OuAn8"},
+ //&db{host: "sum.golang.org", key: "sum.golang.org+033de0ae+BADBADBADBADBADBADBADBADBADBADBADBADBADBADBA"},
+ }
+ for _, d := range dbs {
+ if err := audit(d); err != nil {
+ log.Printf("AUDIT FAIL (%s): %s", d.host, err.Error())
+ }
+ }
+}
+
+func audit(d *db) error {
+ log.Printf("starting audit of %s...", d.host)
+ size, hash, err := d.getLatest()
+ if err != nil {
+ return err
+ }
+ log.Printf("db size %d", size)
+ log.Printf("db hash %s", hash)
+ return nil
+}
+
+type db struct {
+ host string
+ key string
+}
+
+// httpGet makes a GET request to the specified path of the database and
+// returns a byte slice of the response body.
+func (d *db) httpGet(path string) ([]byte, error) {
+ client := &http.Client{}
+ resp, err := client.Get("https://" + d.host + path)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+ var body bytes.Buffer
+ if _, err := io.Copy(&body, resp.Body); err != nil {
+ return nil, fmt.Errorf("could not read response body: %w", err)
+ }
+ return body.Bytes(), nil
+}
+
+// verifyNote takes a signed byte slice, verifies the signature against the
+// db's public key. If successful, the note content is returned, otherwise, an
+// error.
+func (d *db) verifyNote(b []byte) (string, error) {
+ verifier, err := note.NewVerifier(d.key)
+ if err != nil {
+ return "", err
+ }
+ verifiers := note.VerifierList(verifier)
+ msg, err := note.Open(b, verifiers)
+ if err != nil {
+ return "", err
+ }
+ return msg.Text, nil
+}
+
+// getLatest fetches and verifies the latest signed tree head hash and database
+// size.
+func (d *db) getLatest() (int, string, error) {
+ body, err := d.httpGet("/latest")
+ if err != nil {
+ return 0, "", fmt.Errorf("could not fetch latest: %w", err)
+ }
+ msg, err := d.verifyNote(body)
+ if err != nil {
+ return 0, "", fmt.Errorf("could not verify note: %w", err)
+ }
+ parts := strings.Split(msg, "\n")
+ if len(parts) != 4 {
+ return 0, "", fmt.Errorf("could not parse latest: expected %d lines but got %d", 4, len(parts))
+ }
+ size, err := strconv.Atoi(parts[1])
+ if err != nil {
+ return 0, "", fmt.Errorf("could not parse tree size: %w", err)
+ }
+ hash := parts[2]
+ return size, hash, nil
+}