mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-05-06 22:18:28 +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:
+21
-55
@@ -3,6 +3,7 @@ package pgp
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
@@ -18,12 +19,10 @@ var (
|
||||
_ Verifier = &GpgVerifier{}
|
||||
)
|
||||
|
||||
// Skip GPG version check for GPG 1.x
|
||||
var skipGPGVersionCheck bool
|
||||
|
||||
// GpgSigner is implementation of Signer interface using gpg as external program
|
||||
type GpgSigner struct {
|
||||
gpg string
|
||||
version GPGVersion
|
||||
keyRef string
|
||||
keyring, secretKeyring string
|
||||
passphrase, passphraseFile string
|
||||
@@ -55,7 +54,7 @@ func (g *GpgSigner) gpgArgs() []string {
|
||||
if g.keyring != "" {
|
||||
args = append(args, "--no-auto-check-trustdb", "--no-default-keyring", "--keyring", g.keyring)
|
||||
}
|
||||
if g.secretKeyring != "" {
|
||||
if g.secretKeyring != "" && g.version == GPG1x {
|
||||
args = append(args, "--secret-keyring", g.secretKeyring)
|
||||
}
|
||||
|
||||
@@ -64,7 +63,9 @@ func (g *GpgSigner) gpgArgs() []string {
|
||||
}
|
||||
|
||||
if g.passphrase != "" || g.passphraseFile != "" {
|
||||
args = append(args, "--no-use-agent")
|
||||
if g.version == GPG1x {
|
||||
args = append(args, "--no-use-agent")
|
||||
}
|
||||
}
|
||||
|
||||
if g.passphrase != "" {
|
||||
@@ -77,53 +78,21 @@ func (g *GpgSigner) gpgArgs() []string {
|
||||
|
||||
if g.batch {
|
||||
args = append(args, "--no-tty", "--batch")
|
||||
if g.version == GPG21xPlus {
|
||||
args = append(args, "--pinentry-mode", "loopback")
|
||||
}
|
||||
}
|
||||
|
||||
return args
|
||||
}
|
||||
|
||||
func cliVersionCheck(cmd string, marker string) bool {
|
||||
output, err := exec.Command(cmd, "--version").CombinedOutput()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return skipGPGVersionCheck || strings.Contains(string(output), marker)
|
||||
}
|
||||
|
||||
func findSuitableCLI(cmds []string, versionMarker string) string {
|
||||
for _, cmd := range cmds {
|
||||
if cliVersionCheck(cmd, versionMarker) {
|
||||
return cmd
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// We only support gpg1 at this time. Make sure we find a suitable binary.
|
||||
func findGPG1() (string, error) {
|
||||
cmd := findSuitableCLI([]string{"gpg", "gpg1"}, "gpg (GnuPG) 1.")
|
||||
if cmd != "" {
|
||||
return cmd, nil
|
||||
}
|
||||
return "", fmt.Errorf("Couldn't find a suitable gpg executable. Make sure gnupg1 is available as either gpg or gpg1 in $PATH")
|
||||
}
|
||||
|
||||
// We only support gpgv1 at this time. Make sure we find a suitable binary.
|
||||
func findGPGV1() (string, error) {
|
||||
cmd := findSuitableCLI([]string{"gpgv", "gpgv1"}, "gpgv (GnuPG) 1.")
|
||||
if cmd != "" {
|
||||
return cmd, nil
|
||||
}
|
||||
return "", fmt.Errorf("Couldn't find a suitable gpgv executable. Make sure gpgv1 is available as either gpgv or gpgv1 in $PATH")
|
||||
}
|
||||
|
||||
// NewGpgSigner creates a new gpg signer
|
||||
func NewGpgSigner() *GpgSigner {
|
||||
gpg, err := findGPG1()
|
||||
func NewGpgSigner(finder GPGFinder) *GpgSigner {
|
||||
gpg, version, err := finder.FindGPG()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &GpgSigner{gpg: gpg}
|
||||
return &GpgSigner{gpg: gpg, version: version}
|
||||
}
|
||||
|
||||
// Init verifies availability of gpg & presence of keys
|
||||
@@ -171,22 +140,27 @@ func (g *GpgSigner) ClearSign(source string, destination string) error {
|
||||
type GpgVerifier struct {
|
||||
gpg string
|
||||
gpgv string
|
||||
version GPGVersion
|
||||
keyRings []string
|
||||
}
|
||||
|
||||
// NewGpgVerifier creates a new gpg verifier
|
||||
func NewGpgVerifier() *GpgVerifier {
|
||||
gpg, err := findGPG1()
|
||||
func NewGpgVerifier(finder GPGFinder) *GpgVerifier {
|
||||
gpg, versionGPG, err := finder.FindGPG()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
gpgv, err := findGPGV1()
|
||||
gpgv, versionGPGV, err := finder.FindGPGV()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return &GpgVerifier{gpg: gpg, gpgv: gpgv}
|
||||
if versionGPG != versionGPGV {
|
||||
panic(errors.New("gpg and gpgv versions don't match"))
|
||||
}
|
||||
|
||||
return &GpgVerifier{gpg: gpg, gpgv: gpgv, version: versionGPG}
|
||||
}
|
||||
|
||||
// InitKeyring verifies that gpg is installed and some keys are trusted
|
||||
@@ -417,11 +391,3 @@ func (g *GpgVerifier) ExtractClearsigned(clearsigned io.Reader) (text *os.File,
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func init() {
|
||||
skipCheck := os.Getenv("APTLY_SKIP_GPG_VERSION_CHECK")
|
||||
switch strings.ToLower(skipCheck) {
|
||||
case "1", "y", "yes", "true":
|
||||
skipGPGVersionCheck = true
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user