-
Notifications
You must be signed in to change notification settings - Fork 16
/
hashpipe.go
109 lines (88 loc) · 2.17 KB
/
hashpipe.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package main
import (
"bytes"
"flag"
"fmt"
"io/ioutil"
"os"
mh "github.com/jbenet/go-multihash"
mhopts "github.com/jbenet/go-multihash/opts"
)
var usage = `usage: %s [MULTIHASH] <[FILE] >[FILE]
cat untrustedFile | hashpipe <expected-checksum> | trustedContext
hashpipe - boldly journey into the unknown.
It reads from stdin, checks the hash of the content, and outputs it IF AND
ONLY IF it matches the provided hash checksum. This makes executing things
a bit safer, as it requires compromising more communication channels. On
error, hashpipe returns a non-zero error code, failing pipelines.
OPTIONS
`
// flags
var opts *mhopts.Options
var quiet bool
func init() {
flag.Usage = func() {
fmt.Fprintf(os.Stderr, usage, os.Args[0])
flag.PrintDefaults()
}
opts = mhopts.SetupFlags(flag.CommandLine)
quietStr := "quiet output (no newline on checksum, no error text)"
flag.BoolVar(&quiet, "quiet", false, quietStr)
flag.BoolVar(&quiet, "q", false, quietStr+" (shorthand)")
}
func parseFlags(o *mhopts.Options) error {
flag.Parse()
if err := o.ParseError(); err != nil {
return err
}
return nil
}
func getInput(o *mhopts.Options) (mh.Multihash, error) {
args := flag.Args()
if len(args) < 1 {
return nil, fmt.Errorf("multihash is a required argument")
}
raw := args[0]
h, err := mhopts.Decode(o.Encoding, raw)
if err != nil {
return nil, fmt.Errorf("fail to decode multihash '%s': %s", raw, err)
}
return h, nil
}
func run() error {
if err := parseFlags(opts); err != nil {
return err
}
// parse the given checksum
expect, err := getInput(opts)
if err != nil {
return err
}
// have to read all of it before we output any of it :/
input, err := ioutil.ReadAll(os.Stdin)
if err != nil {
return err
}
// calculate the checksum of the input
actual, err := mh.Sum(input, opts.AlgorithmCode, opts.Length)
if err != nil {
return err
}
// ensure checksums match
if !bytes.Equal(expect, actual) {
return mhopts.ErrMatch
}
// ok, checksums matched, write it out
if !quiet {
_, err = os.Stdout.Write(input)
}
return err
}
func main() {
if err := run(); err != nil {
if !quiet {
fmt.Fprintf(os.Stderr, "error: %s\n", err)
}
os.Exit(1)
}
}