Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / mod@v0.3.0 / gosumcheck / main.go
1 // Copyright 2019 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // Gosumcheck checks a go.sum file against a go.sum database server.
6 //
7 // Usage:
8 //
9 //      gosumcheck [-h H] [-k key] [-u url] [-v] go.sum
10 //
11 // The -h flag changes the tile height (default 8).
12 //
13 // The -k flag changes the go.sum database server key.
14 //
15 // The -u flag overrides the URL of the server (usually set from the key name).
16 //
17 // The -v flag enables verbose output.
18 // In particular, it causes gosumcheck to report
19 // the URL and elapsed time for each server request.
20 //
21 // WARNING! WARNING! WARNING!
22 //
23 // Gosumcheck is meant as a proof of concept demo and should not be
24 // used in production scripts or continuous integration testing.
25 // It does not cache any downloaded information from run to run,
26 // making it expensive and also keeping it from detecting server
27 // misbehavior or successful HTTPS man-in-the-middle timeline forks.
28 //
29 // To discourage misuse in automated settings, gosumcheck does not
30 // set any exit status to report whether any problems were found.
31 //
32 package main
33
34 import (
35         "flag"
36         "fmt"
37         "io"
38         "io/ioutil"
39         "log"
40         "net/http"
41         "os"
42         "os/exec"
43         "strings"
44         "sync"
45         "time"
46
47         "golang.org/x/mod/sumdb"
48 )
49
50 func usage() {
51         fmt.Fprintf(os.Stderr, "usage: gosumcheck [-h H] [-k key] [-u url] [-v] go.sum...\n")
52         os.Exit(2)
53 }
54
55 var (
56         height = flag.Int("h", 8, "tile height")
57         vkey   = flag.String("k", "sum.golang.org+033de0ae+Ac4zctda0e5eza+HJyk9SxEdh+s3Ux18htTTAD8OuAn8", "key")
58         url    = flag.String("u", "", "url to server (overriding name)")
59         vflag  = flag.Bool("v", false, "enable verbose output")
60 )
61
62 func main() {
63         log.SetPrefix("notecheck: ")
64         log.SetFlags(0)
65
66         flag.Usage = usage
67         flag.Parse()
68         if flag.NArg() < 1 {
69                 usage()
70         }
71
72         client := sumdb.NewClient(new(clientOps))
73
74         // Look in environment explicitly, so that if 'go env' is old and
75         // doesn't know about GONOSUMDB, we at least get anything
76         // set in the environment.
77         env := os.Getenv("GONOSUMDB")
78         if env == "" {
79                 out, err := exec.Command("go", "env", "GONOSUMDB").CombinedOutput()
80                 if err != nil {
81                         log.Fatalf("go env GONOSUMDB: %v\n%s", err, out)
82                 }
83                 env = strings.TrimSpace(string(out))
84         }
85         client.SetGONOSUMDB(env)
86
87         for _, arg := range flag.Args() {
88                 data, err := ioutil.ReadFile(arg)
89                 if err != nil {
90                         log.Fatal(err)
91                 }
92                 checkGoSum(client, arg, data)
93         }
94 }
95
96 func checkGoSum(client *sumdb.Client, name string, data []byte) {
97         lines := strings.Split(string(data), "\n")
98         if lines[len(lines)-1] != "" {
99                 log.Printf("error: final line missing newline")
100                 return
101         }
102         lines = lines[:len(lines)-1]
103
104         errs := make([]string, len(lines))
105         var wg sync.WaitGroup
106         for i, line := range lines {
107                 wg.Add(1)
108                 go func(i int, line string) {
109                         defer wg.Done()
110                         f := strings.Fields(line)
111                         if len(f) != 3 {
112                                 errs[i] = "invalid number of fields"
113                                 return
114                         }
115
116                         dbLines, err := client.Lookup(f[0], f[1])
117                         if err != nil {
118                                 if err == sumdb.ErrGONOSUMDB {
119                                         errs[i] = fmt.Sprintf("%s@%s: %v", f[0], f[1], err)
120                                 } else {
121                                         // Otherwise Lookup properly adds the prefix itself.
122                                         errs[i] = err.Error()
123                                 }
124                                 return
125                         }
126                         hashAlgPrefix := f[0] + " " + f[1] + " " + f[2][:strings.Index(f[2], ":")+1]
127                         for _, dbLine := range dbLines {
128                                 if dbLine == line {
129                                         return
130                                 }
131                                 if strings.HasPrefix(dbLine, hashAlgPrefix) {
132                                         errs[i] = fmt.Sprintf("%s@%s hash mismatch: have %s, want %s", f[0], f[1], line, dbLine)
133                                         return
134                                 }
135                         }
136                         errs[i] = fmt.Sprintf("%s@%s hash algorithm mismatch: have %s, want one of:\n\t%s", f[0], f[1], line, strings.Join(dbLines, "\n\t"))
137                 }(i, line)
138         }
139         wg.Wait()
140
141         for i, err := range errs {
142                 if err != "" {
143                         fmt.Printf("%s:%d: %s\n", name, i+1, err)
144                 }
145         }
146 }
147
148 type clientOps struct{}
149
150 func (*clientOps) ReadConfig(file string) ([]byte, error) {
151         if file == "key" {
152                 return []byte(*vkey), nil
153         }
154         if strings.HasSuffix(file, "/latest") {
155                 // Looking for cached latest tree head.
156                 // Empty result means empty tree.
157                 return []byte{}, nil
158         }
159         return nil, fmt.Errorf("unknown config %s", file)
160 }
161
162 func (*clientOps) WriteConfig(file string, old, new []byte) error {
163         // Ignore writes.
164         return nil
165 }
166
167 func (*clientOps) ReadCache(file string) ([]byte, error) {
168         return nil, fmt.Errorf("no cache")
169 }
170
171 func (*clientOps) WriteCache(file string, data []byte) {
172         // Ignore writes.
173 }
174
175 func (*clientOps) Log(msg string) {
176         log.Print(msg)
177 }
178
179 func (*clientOps) SecurityError(msg string) {
180         log.Fatal(msg)
181 }
182
183 func init() {
184         http.DefaultClient.Timeout = 1 * time.Minute
185 }
186
187 func (*clientOps) ReadRemote(path string) ([]byte, error) {
188         name := *vkey
189         if i := strings.Index(name, "+"); i >= 0 {
190                 name = name[:i]
191         }
192         start := time.Now()
193         target := "https://" + name + path
194         if *url != "" {
195                 target = *url + path
196         }
197         resp, err := http.Get(target)
198         if err != nil {
199                 return nil, err
200         }
201         defer resp.Body.Close()
202         if resp.StatusCode != 200 {
203                 return nil, fmt.Errorf("GET %v: %v", target, resp.Status)
204         }
205         data, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20))
206         if err != nil {
207                 return nil, err
208         }
209         if *vflag {
210                 fmt.Fprintf(os.Stderr, "%.3fs %s\n", time.Since(start).Seconds(), target)
211         }
212         return data, nil
213 }