mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-06-01 04:40:38 +00:00
Compatibility with GnuPG 1.x and 2.x, auto-detect GnuPG version
* aptly can sign and verify without issues with GnuPG 1.x and 2.x * aptly auto-detects GnuPG version and adapts accordingly * aptly automatically finds suitable GnuPG version Majority of the work was to get unit-tests which can work with GnuPG 1.x & 2.x. Locally I've verified that aptly supports GnuPG 1.4.x & 2.2.x. Travis CI environment is based on trusty, so it runs gpg2 tests with GnuPG 2.0.x. Configuration parameter gpgProvider now supports three values for GnuPG: * gpg (same as before, default): use GnuPG 1.x if available (checks gpg, gpg1), otherwise uses GnuPG 2.x; for aptly users who already have GnuPG 1.x environment (as it was the only supported version) nothing should change; new users might start with GnuPG 2.x if that's their installed version * gpg1 looks for GnuPG 1.x only, fails otherwise * gpg2 looks for GnuPG 2.x only, fails otherwise
This commit is contained in:
@@ -0,0 +1,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
|
||||
}
|
||||
Reference in New Issue
Block a user