forked from aptly-dev/aptly
/
gnupg_finder.go
149 lines (122 loc) · 3.4 KB
/
gnupg_finder.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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package pgp
import (
"errors"
"os/exec"
"regexp"
"strings"
)
// GPGVersion stores discovered GPG version
type GPGVersion int
// GPG version as discovered
const (
GPG1x GPGVersion = 1
GPG20x GPGVersion = 2
GPG21xPlus GPGVersion = 3
)
var gpgVersionRegex = regexp.MustCompile(`\(GnuPG\) (\d)\.(\d)`)
// GPGFinder implement search for gpg executables and returns version of discovered executables
type GPGFinder interface {
FindGPG() (gpg string, version GPGVersion, err error)
FindGPGV() (gpgv string, version GPGVersion, err error)
}
type pathGPGFinder struct {
gpgNames []string
gpgvNames []string
errorMessage string
expectedVersionSubstring string
}
type iteratingGPGFinder struct {
finders []GPGFinder
errorMessage string
}
// GPGDefaultFinder looks for GPG1 first, but falls back to GPG2 if GPG1 is not available
func GPGDefaultFinder() GPGFinder {
return &iteratingGPGFinder{
finders: []GPGFinder{GPG1Finder(), GPG2Finder()},
errorMessage: "Couldn't find a suitable gpg executable. Make sure gnupg is installed",
}
}
// GPG1Finder looks for GnuPG1.x only
func GPG1Finder() GPGFinder {
return &pathGPGFinder{
gpgNames: []string{"gpg", "gpg1"},
gpgvNames: []string{"gpgv", "gpgv1"},
expectedVersionSubstring: "(GnuPG) 1.",
errorMessage: "Couldn't find a suitable gpg executable. Make sure gnupg1 is available as either gpg(v) or gpg(v)1 in $PATH",
}
}
// GPG2Finder looks for GnuPG2.x only
func GPG2Finder() GPGFinder {
return &pathGPGFinder{
gpgNames: []string{"gpg", "gpg2"},
gpgvNames: []string{"gpgv", "gpgv2"},
expectedVersionSubstring: "(GnuPG) 2.",
errorMessage: "Couldn't find a suitable gpg executable. Make sure gnupg2 is available as either gpg(v) or gpg(v)2 in $PATH",
}
}
func (pgf *pathGPGFinder) FindGPG() (gpg string, version GPGVersion, err error) {
for _, cmd := range pgf.gpgNames {
var result bool
result, version = cliVersionCheck(cmd, pgf.expectedVersionSubstring)
if result {
gpg = cmd
break
}
}
if gpg == "" {
err = errors.New(pgf.errorMessage)
}
return
}
func (pgf *pathGPGFinder) FindGPGV() (gpgv string, version GPGVersion, err error) {
for _, cmd := range pgf.gpgvNames {
var result bool
result, version = cliVersionCheck(cmd, pgf.expectedVersionSubstring)
if result {
gpgv = cmd
break
}
}
if gpgv == "" {
err = errors.New(pgf.errorMessage)
}
return
}
func (it *iteratingGPGFinder) FindGPG() (gpg string, version GPGVersion, err error) {
for _, finder := range it.finders {
gpg, version, err = finder.FindGPG()
if err == nil {
return
}
}
err = errors.New(it.errorMessage)
return
}
func (it *iteratingGPGFinder) FindGPGV() (gpg string, version GPGVersion, err error) {
for _, finder := range it.finders {
gpg, version, err = finder.FindGPGV()
if err == nil {
return
}
}
err = errors.New(it.errorMessage)
return
}
func cliVersionCheck(cmd string, marker string) (result bool, version GPGVersion) {
output, err := exec.Command(cmd, "--version").CombinedOutput()
if err != nil {
return
}
strOutput := string(output)
result = strings.Contains(strOutput, marker)
version = GPG21xPlus
matches := gpgVersionRegex.FindStringSubmatch(strOutput)
if matches != nil {
if matches[1] == "1" {
version = GPG1x
} else if matches[1] == "2" && matches[2] == "0" {
version = GPG20x
}
}
return
}