mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-01-11 03:11:50 +00:00
* 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
150 lines
3.4 KiB
Go
150 lines
3.4 KiB
Go
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
|
|
}
|