mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-07-27 13:57:46 +00:00
Merge pull request #575 from smira/pgp-refactoring
Refactor GPG signer/verifier
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
GOVERSION=$(shell go version | awk '{print $$3;}')
|
GOVERSION=$(shell go version | awk '{print $$3;}')
|
||||||
VERSION=$(shell git describe --tags | sed 's@^v@@' | sed 's@-@+@g')
|
VERSION=$(shell git describe --tags | sed 's@^v@@' | sed 's@-@+@g')
|
||||||
PACKAGES=context database deb files http query swift s3 utils
|
PACKAGES=context database deb files gpg http query swift s3 utils
|
||||||
PYTHON?=python
|
PYTHON?=python
|
||||||
TESTS?=
|
TESTS?=
|
||||||
BINPATH?=$(GOPATH)/bin
|
BINPATH?=$(GOPATH)/bin
|
||||||
|
|||||||
+3
-2
@@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/smira/aptly/deb"
|
"github.com/smira/aptly/deb"
|
||||||
|
"github.com/smira/aptly/pgp"
|
||||||
"github.com/smira/aptly/utils"
|
"github.com/smira/aptly/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -20,12 +21,12 @@ type SigningOptions struct {
|
|||||||
PassphraseFile string
|
PassphraseFile string
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSigner(options *SigningOptions) (utils.Signer, error) {
|
func getSigner(options *SigningOptions) (pgp.Signer, error) {
|
||||||
if options.Skip {
|
if options.Skip {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
signer := &utils.GpgSigner{}
|
signer := &pgp.GpgSigner{}
|
||||||
signer.SetKey(options.GpgKey)
|
signer.SetKey(options.GpgKey)
|
||||||
signer.SetKeyRing(options.Keyring, options.SecretKeyring)
|
signer.SetKeyRing(options.Keyring, options.SecretKeyring)
|
||||||
signer.SetPassphrase(options.Passphrase, options.PassphraseFile)
|
signer.SetPassphrase(options.Passphrase, options.PassphraseFile)
|
||||||
|
|||||||
+2
-1
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/smira/aptly/aptly"
|
"github.com/smira/aptly/aptly"
|
||||||
"github.com/smira/aptly/database"
|
"github.com/smira/aptly/database"
|
||||||
"github.com/smira/aptly/deb"
|
"github.com/smira/aptly/deb"
|
||||||
|
"github.com/smira/aptly/pgp"
|
||||||
"github.com/smira/aptly/utils"
|
"github.com/smira/aptly/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -296,7 +297,7 @@ func apiReposPackageFromDir(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
verifier := &utils.GpgVerifier{}
|
verifier := &pgp.GpgVerifier{}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
sources []string
|
sources []string
|
||||||
|
|||||||
+3
-3
@@ -3,19 +3,19 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/smira/aptly/utils"
|
"github.com/smira/aptly/pgp"
|
||||||
"github.com/smira/commander"
|
"github.com/smira/commander"
|
||||||
"github.com/smira/flag"
|
"github.com/smira/flag"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getVerifier(flags *flag.FlagSet) (utils.Verifier, error) {
|
func getVerifier(flags *flag.FlagSet) (pgp.Verifier, error) {
|
||||||
if LookupOption(context.Config().GpgDisableVerify, flags, "ignore-signatures") {
|
if LookupOption(context.Config().GpgDisableVerify, flags, "ignore-signatures") {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
keyRings := flags.Lookup("keyring").Value.Get().([]string)
|
keyRings := flags.Lookup("keyring").Value.Get().([]string)
|
||||||
|
|
||||||
verifier := &utils.GpgVerifier{}
|
verifier := &pgp.GpgVerifier{}
|
||||||
for _, keyRing := range keyRings {
|
for _, keyRing := range keyRings {
|
||||||
verifier.AddKeyring(keyRing)
|
verifier.AddKeyring(keyRing)
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -1,17 +1,17 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/smira/aptly/utils"
|
"github.com/smira/aptly/pgp"
|
||||||
"github.com/smira/commander"
|
"github.com/smira/commander"
|
||||||
"github.com/smira/flag"
|
"github.com/smira/flag"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getSigner(flags *flag.FlagSet) (utils.Signer, error) {
|
func getSigner(flags *flag.FlagSet) (pgp.Signer, error) {
|
||||||
if LookupOption(context.Config().GpgDisableSign, flags, "skip-signing") {
|
if LookupOption(context.Config().GpgDisableSign, flags, "skip-signing") {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
signer := &utils.GpgSigner{}
|
signer := &pgp.GpgSigner{}
|
||||||
signer.SetKey(flags.Lookup("gpg-key").Value.String())
|
signer.SetKey(flags.Lookup("gpg-key").Value.String())
|
||||||
signer.SetKeyRing(flags.Lookup("keyring").Value.String(), flags.Lookup("secret-keyring").Value.String())
|
signer.SetKeyRing(flags.Lookup("keyring").Value.String(), flags.Lookup("secret-keyring").Value.String())
|
||||||
signer.SetPassphrase(flags.Lookup("passphrase").Value.String(), flags.Lookup("passphrase-file").Value.String())
|
signer.SetPassphrase(flags.Lookup("passphrase").Value.String(), flags.Lookup("passphrase-file").Value.String())
|
||||||
|
|||||||
+2
-1
@@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/smira/aptly/aptly"
|
"github.com/smira/aptly/aptly"
|
||||||
"github.com/smira/aptly/deb"
|
"github.com/smira/aptly/deb"
|
||||||
|
"github.com/smira/aptly/pgp"
|
||||||
"github.com/smira/aptly/utils"
|
"github.com/smira/aptly/utils"
|
||||||
"github.com/smira/commander"
|
"github.com/smira/commander"
|
||||||
"github.com/smira/flag"
|
"github.com/smira/flag"
|
||||||
@@ -20,7 +21,7 @@ func aptlyRepoAdd(cmd *commander.Command, args []string) error {
|
|||||||
|
|
||||||
name := args[0]
|
name := args[0]
|
||||||
|
|
||||||
verifier := &utils.GpgVerifier{}
|
verifier := &pgp.GpgVerifier{}
|
||||||
|
|
||||||
repo, err := context.CollectionFactory().LocalRepoCollection().ByName(name)
|
repo, err := context.CollectionFactory().LocalRepoCollection().ByName(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+2
-1
@@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/smira/aptly/aptly"
|
"github.com/smira/aptly/aptly"
|
||||||
"github.com/smira/aptly/deb"
|
"github.com/smira/aptly/deb"
|
||||||
|
"github.com/smira/aptly/pgp"
|
||||||
"github.com/smira/aptly/query"
|
"github.com/smira/aptly/query"
|
||||||
"github.com/smira/aptly/utils"
|
"github.com/smira/aptly/utils"
|
||||||
"github.com/smira/commander"
|
"github.com/smira/commander"
|
||||||
@@ -28,7 +29,7 @@ func aptlyRepoInclude(cmd *commander.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if verifier == nil {
|
if verifier == nil {
|
||||||
verifier = &utils.GpgVerifier{}
|
verifier = &pgp.GpgVerifier{}
|
||||||
}
|
}
|
||||||
|
|
||||||
forceReplace := context.Flags().Lookup("force-replace").Value.Get().(bool)
|
forceReplace := context.Flags().Lookup("force-replace").Value.Get().(bool)
|
||||||
|
|||||||
+4
-3
@@ -9,6 +9,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/smira/aptly/aptly"
|
"github.com/smira/aptly/aptly"
|
||||||
|
"github.com/smira/aptly/pgp"
|
||||||
"github.com/smira/aptly/utils"
|
"github.com/smira/aptly/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -23,7 +24,7 @@ type Changes struct {
|
|||||||
Binary []string
|
Binary []string
|
||||||
Architectures []string
|
Architectures []string
|
||||||
Stanza Stanza
|
Stanza Stanza
|
||||||
SignatureKeys []utils.GpgKey
|
SignatureKeys []pgp.Key
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewChanges moves .changes file into temporary directory and creates Changes structure
|
// NewChanges moves .changes file into temporary directory and creates Changes structure
|
||||||
@@ -50,7 +51,7 @@ func NewChanges(path string) (*Changes, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// VerifyAndParse does optional signature verification and parses changes files
|
// VerifyAndParse does optional signature verification and parses changes files
|
||||||
func (c *Changes) VerifyAndParse(acceptUnsigned, ignoreSignature bool, verifier utils.Verifier) error {
|
func (c *Changes) VerifyAndParse(acceptUnsigned, ignoreSignature bool, verifier pgp.Verifier) error {
|
||||||
input, err := os.Open(filepath.Join(c.TempDir, c.ChangesName))
|
input, err := os.Open(filepath.Join(c.TempDir, c.ChangesName))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -69,7 +70,7 @@ func (c *Changes) VerifyAndParse(acceptUnsigned, ignoreSignature bool, verifier
|
|||||||
}
|
}
|
||||||
|
|
||||||
if isClearSigned && !ignoreSignature {
|
if isClearSigned && !ignoreSignature {
|
||||||
var keyInfo *utils.GpgKeyInfo
|
var keyInfo *pgp.KeyInfo
|
||||||
keyInfo, err = verifier.VerifyClearsigned(input, false)
|
keyInfo, err = verifier.VerifyClearsigned(input, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
+2
-2
@@ -14,7 +14,7 @@ import (
|
|||||||
"github.com/mkrautz/goar"
|
"github.com/mkrautz/goar"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"github.com/smira/aptly/utils"
|
"github.com/smira/aptly/pgp"
|
||||||
"github.com/smira/go-xz"
|
"github.com/smira/go-xz"
|
||||||
"github.com/smira/lzma"
|
"github.com/smira/lzma"
|
||||||
)
|
)
|
||||||
@@ -76,7 +76,7 @@ func GetControlFileFromDeb(packageFile string) (Stanza, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetControlFileFromDsc reads control file from dsc package
|
// GetControlFileFromDsc reads control file from dsc package
|
||||||
func GetControlFileFromDsc(dscFile string, verifier utils.Verifier) (Stanza, error) {
|
func GetControlFileFromDsc(dscFile string, verifier pgp.Verifier) (Stanza, error) {
|
||||||
file, err := os.Open(dscFile)
|
file, err := os.Open(dscFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
+2
-2
@@ -5,7 +5,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"github.com/smira/aptly/utils"
|
"github.com/smira/aptly/pgp"
|
||||||
|
|
||||||
. "gopkg.in/check.v1"
|
. "gopkg.in/check.v1"
|
||||||
)
|
)
|
||||||
@@ -39,7 +39,7 @@ func (s *DebSuite) TestGetControlFileFromDeb(c *C) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *DebSuite) TestGetControlFileFromDsc(c *C) {
|
func (s *DebSuite) TestGetControlFileFromDsc(c *C) {
|
||||||
verifier := &utils.GpgVerifier{}
|
verifier := &pgp.GpgVerifier{}
|
||||||
|
|
||||||
_, err := GetControlFileFromDsc("/no/such/file", verifier)
|
_, err := GetControlFileFromDsc("/no/such/file", verifier)
|
||||||
c.Check(err, ErrorMatches, ".*no such file or directory")
|
c.Check(err, ErrorMatches, ".*no such file or directory")
|
||||||
|
|||||||
+2
-1
@@ -7,6 +7,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/smira/aptly/aptly"
|
"github.com/smira/aptly/aptly"
|
||||||
|
"github.com/smira/aptly/pgp"
|
||||||
"github.com/smira/aptly/utils"
|
"github.com/smira/aptly/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -59,7 +60,7 @@ func CollectPackageFiles(locations []string, reporter aptly.ResultReporter) (pac
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ImportPackageFiles imports files into local repository
|
// ImportPackageFiles imports files into local repository
|
||||||
func ImportPackageFiles(list *PackageList, packageFiles []string, forceReplace bool, verifier utils.Verifier,
|
func ImportPackageFiles(list *PackageList, packageFiles []string, forceReplace bool, verifier pgp.Verifier,
|
||||||
pool aptly.PackagePool, collection *PackageCollection, reporter aptly.ResultReporter, restriction PackageQuery,
|
pool aptly.PackagePool, collection *PackageCollection, reporter aptly.ResultReporter, restriction PackageQuery,
|
||||||
checksumStorage aptly.ChecksumStorage) (processedFiles []string, failedFiles []string, err error) {
|
checksumStorage aptly.ChecksumStorage) (processedFiles []string, failedFiles []string, err error) {
|
||||||
if forceReplace {
|
if forceReplace {
|
||||||
|
|||||||
+2
-1
@@ -8,6 +8,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/smira/aptly/aptly"
|
"github.com/smira/aptly/aptly"
|
||||||
|
"github.com/smira/aptly/pgp"
|
||||||
"github.com/smira/aptly/utils"
|
"github.com/smira/aptly/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -48,7 +49,7 @@ func (file *indexFile) BufWriter() (*bufio.Writer, error) {
|
|||||||
return file.w, nil
|
return file.w, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (file *indexFile) Finalize(signer utils.Signer) error {
|
func (file *indexFile) Finalize(signer pgp.Signer) error {
|
||||||
if file.w == nil {
|
if file.w == nil {
|
||||||
if file.discardable {
|
if file.discardable {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
+2
-1
@@ -19,6 +19,7 @@ import (
|
|||||||
|
|
||||||
"github.com/smira/aptly/aptly"
|
"github.com/smira/aptly/aptly"
|
||||||
"github.com/smira/aptly/database"
|
"github.com/smira/aptly/database"
|
||||||
|
"github.com/smira/aptly/pgp"
|
||||||
"github.com/smira/aptly/utils"
|
"github.com/smira/aptly/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -447,7 +448,7 @@ func (p *PublishedRepo) GetLabel() string {
|
|||||||
|
|
||||||
// Publish publishes snapshot (repository) contents, links package files, generates Packages & Release files, signs them
|
// Publish publishes snapshot (repository) contents, links package files, generates Packages & Release files, signs them
|
||||||
func (p *PublishedRepo) Publish(packagePool aptly.PackagePool, publishedStorageProvider aptly.PublishedStorageProvider,
|
func (p *PublishedRepo) Publish(packagePool aptly.PackagePool, publishedStorageProvider aptly.PublishedStorageProvider,
|
||||||
collectionFactory *CollectionFactory, signer utils.Signer, progress aptly.Progress, forceOverwrite bool) error {
|
collectionFactory *CollectionFactory, signer pgp.Signer, progress aptly.Progress, forceOverwrite bool) error {
|
||||||
publishedStorage := publishedStorageProvider.GetPublishedStorage(p.Storage)
|
publishedStorage := publishedStorageProvider.GetPublishedStorage(p.Storage)
|
||||||
|
|
||||||
err := publishedStorage.MkDir(filepath.Join(p.Prefix, "pool"))
|
err := publishedStorage.MkDir(filepath.Join(p.Prefix, "pool"))
|
||||||
|
|||||||
+2
-1
@@ -17,6 +17,7 @@ import (
|
|||||||
"github.com/smira/aptly/aptly"
|
"github.com/smira/aptly/aptly"
|
||||||
"github.com/smira/aptly/database"
|
"github.com/smira/aptly/database"
|
||||||
"github.com/smira/aptly/http"
|
"github.com/smira/aptly/http"
|
||||||
|
"github.com/smira/aptly/pgp"
|
||||||
"github.com/smira/aptly/utils"
|
"github.com/smira/aptly/utils"
|
||||||
"github.com/smira/go-uuid/uuid"
|
"github.com/smira/go-uuid/uuid"
|
||||||
"github.com/ugorji/go/codec"
|
"github.com/ugorji/go/codec"
|
||||||
@@ -243,7 +244,7 @@ func (repo *RemoteRepo) PackageURL(filename string) *url.URL {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fetch updates information about repository
|
// Fetch updates information about repository
|
||||||
func (repo *RemoteRepo) Fetch(d aptly.Downloader, verifier utils.Verifier) error {
|
func (repo *RemoteRepo) Fetch(d aptly.Downloader, verifier pgp.Verifier) error {
|
||||||
var (
|
var (
|
||||||
release, inrelease, releasesig *os.File
|
release, inrelease, releasesig *os.File
|
||||||
err error
|
err error
|
||||||
|
|||||||
+2
-1
@@ -12,6 +12,7 @@ import (
|
|||||||
"github.com/smira/aptly/database"
|
"github.com/smira/aptly/database"
|
||||||
"github.com/smira/aptly/files"
|
"github.com/smira/aptly/files"
|
||||||
"github.com/smira/aptly/http"
|
"github.com/smira/aptly/http"
|
||||||
|
"github.com/smira/aptly/pgp"
|
||||||
"github.com/smira/aptly/utils"
|
"github.com/smira/aptly/utils"
|
||||||
|
|
||||||
. "gopkg.in/check.v1"
|
. "gopkg.in/check.v1"
|
||||||
@@ -31,7 +32,7 @@ func (n *NullVerifier) VerifyDetachedSignature(signature, cleartext io.Reader) e
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *NullVerifier) VerifyClearsigned(clearsigned io.Reader, hint bool) (*utils.GpgKeyInfo, error) {
|
func (n *NullVerifier) VerifyClearsigned(clearsigned io.Reader, hint bool) (*pgp.KeyInfo, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -6,6 +6,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/DisposaBoy/JsonConfigReader"
|
"github.com/DisposaBoy/JsonConfigReader"
|
||||||
|
"github.com/smira/aptly/pgp"
|
||||||
"github.com/smira/aptly/utils"
|
"github.com/smira/aptly/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -85,7 +86,7 @@ func (u *Uploaders) IsAllowed(changes *Changes) error {
|
|||||||
deny := u.ExpandGroups(rule.Deny)
|
deny := u.ExpandGroups(rule.Deny)
|
||||||
for _, key := range changes.SignatureKeys {
|
for _, key := range changes.SignatureKeys {
|
||||||
for _, item := range deny {
|
for _, item := range deny {
|
||||||
if item == "*" || key.Matches(utils.GpgKey(item)) {
|
if item == "*" || key.Matches(pgp.Key(item)) {
|
||||||
return fmt.Errorf("denied according to rule: %s", rule)
|
return fmt.Errorf("denied according to rule: %s", rule)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -94,7 +95,7 @@ func (u *Uploaders) IsAllowed(changes *Changes) error {
|
|||||||
allow := u.ExpandGroups(rule.Allow)
|
allow := u.ExpandGroups(rule.Allow)
|
||||||
for _, key := range changes.SignatureKeys {
|
for _, key := range changes.SignatureKeys {
|
||||||
for _, item := range allow {
|
for _, item := range allow {
|
||||||
if item == "*" || key.Matches(utils.GpgKey(item)) {
|
if item == "*" || key.Matches(pgp.Key(item)) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package deb
|
package deb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/smira/aptly/utils"
|
"github.com/smira/aptly/pgp"
|
||||||
. "gopkg.in/check.v1"
|
. "gopkg.in/check.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -58,24 +58,24 @@ func (s *UploadersSuite) TestIsAllowed(c *C) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// no keys - not allowed
|
// no keys - not allowed
|
||||||
c.Check(u.IsAllowed(&Changes{SignatureKeys: []utils.GpgKey{}, Stanza: Stanza{"Source": "calamares"}}), ErrorMatches, "denied as no rule matches")
|
c.Check(u.IsAllowed(&Changes{SignatureKeys: []pgp.Key{}, Stanza: Stanza{"Source": "calamares"}}), ErrorMatches, "denied as no rule matches")
|
||||||
|
|
||||||
// no rule - not allowed
|
// no rule - not allowed
|
||||||
c.Check(u.IsAllowed(&Changes{SignatureKeys: []utils.GpgKey{"37E1C17570096AD1", "EC4B033C70096AD1"}, Stanza: Stanza{"Source": "unknown-calamares"}}), ErrorMatches, "denied as no rule matches")
|
c.Check(u.IsAllowed(&Changes{SignatureKeys: []pgp.Key{"37E1C17570096AD1", "EC4B033C70096AD1"}, Stanza: Stanza{"Source": "unknown-calamares"}}), ErrorMatches, "denied as no rule matches")
|
||||||
|
|
||||||
// first rule: allow anyone do stuff with calamares
|
// first rule: allow anyone do stuff with calamares
|
||||||
c.Check(u.IsAllowed(&Changes{SignatureKeys: []utils.GpgKey{"ABCD1234", "1234ABCD"}, Stanza: Stanza{"Source": "calamares"}}), IsNil)
|
c.Check(u.IsAllowed(&Changes{SignatureKeys: []pgp.Key{"ABCD1234", "1234ABCD"}, Stanza: Stanza{"Source": "calamares"}}), IsNil)
|
||||||
|
|
||||||
// second rule: nobody is allowed to do stuff with never-calamares
|
// second rule: nobody is allowed to do stuff with never-calamares
|
||||||
c.Check(u.IsAllowed(&Changes{SignatureKeys: []utils.GpgKey{"ABCD1234", "1234ABCD"}, Stanza: Stanza{"Source": "never-calamares"}}),
|
c.Check(u.IsAllowed(&Changes{SignatureKeys: []pgp.Key{"ABCD1234", "1234ABCD"}, Stanza: Stanza{"Source": "never-calamares"}}),
|
||||||
ErrorMatches, "denied according to rule: {\"condition\":\"\",\"allow\":null,\"deny\":\\[\"\\*\"\\]}")
|
ErrorMatches, "denied according to rule: {\"condition\":\"\",\"allow\":null,\"deny\":\\[\"\\*\"\\]}")
|
||||||
|
|
||||||
// third rule: anyone from the group or explicit key
|
// third rule: anyone from the group or explicit key
|
||||||
c.Check(u.IsAllowed(&Changes{SignatureKeys: []utils.GpgKey{"45678901", "12345678"}, Stanza: Stanza{"Source": "some-calamares"}}), IsNil)
|
c.Check(u.IsAllowed(&Changes{SignatureKeys: []pgp.Key{"45678901", "12345678"}, Stanza: Stanza{"Source": "some-calamares"}}), IsNil)
|
||||||
c.Check(u.IsAllowed(&Changes{SignatureKeys: []utils.GpgKey{"37E1C17570096AD1"}, Stanza: Stanza{"Source": "some-calamares"}}), IsNil)
|
c.Check(u.IsAllowed(&Changes{SignatureKeys: []pgp.Key{"37E1C17570096AD1"}, Stanza: Stanza{"Source": "some-calamares"}}), IsNil)
|
||||||
c.Check(u.IsAllowed(&Changes{SignatureKeys: []utils.GpgKey{"70096AD1"}, Stanza: Stanza{"Source": "some-calamares"}}), IsNil)
|
c.Check(u.IsAllowed(&Changes{SignatureKeys: []pgp.Key{"70096AD1"}, Stanza: Stanza{"Source": "some-calamares"}}), IsNil)
|
||||||
|
|
||||||
// fourth rule: some are not allowed
|
// fourth rule: some are not allowed
|
||||||
c.Check(u.IsAllowed(&Changes{SignatureKeys: []utils.GpgKey{"ABCD1234", "45678901"}, Stanza: Stanza{"Source": "some-calamares"}}),
|
c.Check(u.IsAllowed(&Changes{SignatureKeys: []pgp.Key{"ABCD1234", "45678901"}, Stanza: Stanza{"Source": "some-calamares"}}),
|
||||||
ErrorMatches, "denied according to rule: {\"condition\":\"\",\"allow\":null,\"deny\":\\[\"45678901\",\"12345678\"\\]}")
|
ErrorMatches, "denied according to rule: {\"condition\":\"\",\"allow\":null,\"deny\":\\[\"45678901\",\"12345678\"\\]}")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package utils
|
package pgp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
@@ -12,60 +12,13 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Signer interface describes facility implementing signing of files
|
|
||||||
type Signer interface {
|
|
||||||
Init() error
|
|
||||||
SetKey(keyRef string)
|
|
||||||
SetKeyRing(keyring, secretKeyring string)
|
|
||||||
SetPassphrase(passphrase, passphraseFile string)
|
|
||||||
SetBatch(batch bool)
|
|
||||||
DetachedSign(source string, destination string) error
|
|
||||||
ClearSign(source string, destination string) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verifier interface describes signature verification factility
|
|
||||||
type Verifier interface {
|
|
||||||
InitKeyring() error
|
|
||||||
AddKeyring(keyring string)
|
|
||||||
VerifyDetachedSignature(signature, cleartext io.Reader) error
|
|
||||||
IsClearSigned(clearsigned io.Reader) (bool, error)
|
|
||||||
VerifyClearsigned(clearsigned io.Reader, showKeyTip bool) (*GpgKeyInfo, error)
|
|
||||||
ExtractClearsigned(clearsigned io.Reader) (text *os.File, err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test interface
|
// Test interface
|
||||||
var (
|
var (
|
||||||
_ Signer = &GpgSigner{}
|
_ Signer = &GpgSigner{}
|
||||||
_ Verifier = &GpgVerifier{}
|
_ Verifier = &GpgVerifier{}
|
||||||
)
|
)
|
||||||
|
|
||||||
// GpgKey is key in GPG representation
|
// GpgSigner is implementation of Signer interface using gpg as external program
|
||||||
type GpgKey string
|
|
||||||
|
|
||||||
// Matches checks two keys for equality
|
|
||||||
func (key1 GpgKey) Matches(key2 GpgKey) bool {
|
|
||||||
if key1 == key2 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(key1) == 8 && len(key2) == 16 {
|
|
||||||
return key1 == key2[8:]
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(key1) == 16 && len(key2) == 8 {
|
|
||||||
return key1[8:] == key2
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// GpgKeyInfo is response from signature verification
|
|
||||||
type GpgKeyInfo struct {
|
|
||||||
GoodKeys []GpgKey
|
|
||||||
MissingKeys []GpgKey
|
|
||||||
}
|
|
||||||
|
|
||||||
// GpgSigner is implementation of Signer interface using gpg
|
|
||||||
type GpgSigner struct {
|
type GpgSigner struct {
|
||||||
keyRef string
|
keyRef string
|
||||||
keyring, secretKeyring string
|
keyring, secretKeyring string
|
||||||
@@ -166,7 +119,7 @@ func (g *GpgSigner) ClearSign(source string, destination string) error {
|
|||||||
return cmd.Run()
|
return cmd.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GpgVerifier is implementation of Verifier interface using gpgv
|
// GpgVerifier is implementation of Verifier interface using gpgv as external program
|
||||||
type GpgVerifier struct {
|
type GpgVerifier struct {
|
||||||
keyRings []string
|
keyRings []string
|
||||||
}
|
}
|
||||||
@@ -209,7 +162,7 @@ func (g *GpgVerifier) argsKeyrings() (args []string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GpgVerifier) runGpgv(args []string, context string, showKeyTip bool) (*GpgKeyInfo, error) {
|
func (g *GpgVerifier) runGpgv(args []string, context string, showKeyTip bool) (*KeyInfo, error) {
|
||||||
args = append([]string{"--status-fd", "3"}, args...)
|
args = append([]string{"--status-fd", "3"}, args...)
|
||||||
cmd := exec.Command("gpgv", args...)
|
cmd := exec.Command("gpgv", args...)
|
||||||
|
|
||||||
@@ -250,15 +203,15 @@ func (g *GpgVerifier) runGpgv(args []string, context string, showKeyTip bool) (*
|
|||||||
|
|
||||||
statusr := bufio.NewScanner(tempf)
|
statusr := bufio.NewScanner(tempf)
|
||||||
|
|
||||||
result := &GpgKeyInfo{}
|
result := &KeyInfo{}
|
||||||
|
|
||||||
for statusr.Scan() {
|
for statusr.Scan() {
|
||||||
line := strings.TrimSpace(statusr.Text())
|
line := strings.TrimSpace(statusr.Text())
|
||||||
|
|
||||||
if strings.HasPrefix(line, "[GNUPG:] GOODSIG ") {
|
if strings.HasPrefix(line, "[GNUPG:] GOODSIG ") {
|
||||||
result.GoodKeys = append(result.GoodKeys, GpgKey(strings.Fields(line)[2]))
|
result.GoodKeys = append(result.GoodKeys, Key(strings.Fields(line)[2]))
|
||||||
} else if strings.HasPrefix(line, "[GNUPG:] NO_PUBKEY ") {
|
} else if strings.HasPrefix(line, "[GNUPG:] NO_PUBKEY ") {
|
||||||
result.MissingKeys = append(result.MissingKeys, GpgKey(strings.Fields(line)[2]))
|
result.MissingKeys = append(result.MissingKeys, Key(strings.Fields(line)[2]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,7 +286,7 @@ func (g *GpgVerifier) IsClearSigned(clearsigned io.Reader) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// VerifyClearsigned verifies clearsigned file using gpgv
|
// VerifyClearsigned verifies clearsigned file using gpgv
|
||||||
func (g *GpgVerifier) VerifyClearsigned(clearsigned io.Reader, showKeyTip bool) (*GpgKeyInfo, error) {
|
func (g *GpgVerifier) VerifyClearsigned(clearsigned io.Reader, showKeyTip bool) (*KeyInfo, error) {
|
||||||
args := g.argsKeyrings()
|
args := g.argsKeyrings()
|
||||||
|
|
||||||
clearf, err := ioutil.TempFile("", "aptly-gpg")
|
clearf, err := ioutil.TempFile("", "aptly-gpg")
|
||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
// Package pgp provides interface to signature generation and validation
|
||||||
|
package pgp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Key is key in PGP representation
|
||||||
|
type Key string
|
||||||
|
|
||||||
|
// Matches checks two keys for equality
|
||||||
|
func (key1 Key) Matches(key2 Key) bool {
|
||||||
|
if key1 == key2 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(key1) == 8 && len(key2) == 16 {
|
||||||
|
return key1 == key2[8:]
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(key1) == 16 && len(key2) == 8 {
|
||||||
|
return key1[8:] == key2
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyInfo is response from signature verification
|
||||||
|
type KeyInfo struct {
|
||||||
|
GoodKeys []Key
|
||||||
|
MissingKeys []Key
|
||||||
|
}
|
||||||
|
|
||||||
|
// Signer interface describes facility implementing signing of files
|
||||||
|
type Signer interface {
|
||||||
|
Init() error
|
||||||
|
SetKey(keyRef string)
|
||||||
|
SetKeyRing(keyring, secretKeyring string)
|
||||||
|
SetPassphrase(passphrase, passphraseFile string)
|
||||||
|
SetBatch(batch bool)
|
||||||
|
DetachedSign(source string, destination string) error
|
||||||
|
ClearSign(source string, destination string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verifier interface describes signature verification factility
|
||||||
|
type Verifier interface {
|
||||||
|
InitKeyring() error
|
||||||
|
AddKeyring(keyring string)
|
||||||
|
VerifyDetachedSignature(signature, cleartext io.Reader) error
|
||||||
|
IsClearSigned(clearsigned io.Reader) (bool, error)
|
||||||
|
VerifyClearsigned(clearsigned io.Reader, showKeyTip bool) (*KeyInfo, error)
|
||||||
|
ExtractClearsigned(clearsigned io.Reader) (text *os.File, err error)
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package pgp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
. "gopkg.in/check.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Launch gocheck tests
|
||||||
|
func Test(t *testing.T) {
|
||||||
|
TestingT(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
type PGPSuite struct{}
|
||||||
|
|
||||||
|
var _ = Suite(&PGPSuite{})
|
||||||
|
|
||||||
|
func (s *PGPSuite) TestKeyMatch(c *C) {
|
||||||
|
c.Check(Key("EC4B033C70096AD1").Matches(Key("EC4B033C70096AD1")), Equals, true)
|
||||||
|
c.Check(Key("37E1C17570096AD1").Matches(Key("EC4B033C70096AD1")), Equals, false)
|
||||||
|
|
||||||
|
c.Check(Key("70096AD1").Matches(Key("70096AD1")), Equals, true)
|
||||||
|
c.Check(Key("70096AD1").Matches(Key("EC4B033C")), Equals, false)
|
||||||
|
|
||||||
|
c.Check(Key("37E1C17570096AD1").Matches(Key("70096AD1")), Equals, true)
|
||||||
|
c.Check(Key("70096AD1").Matches(Key("EC4B033C70096AD1")), Equals, true)
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
gpgv: DSA key ID 16DB3E6D
|
gpgv: DSA key ID 16DB3E6D
|
||||||
gpgv: Good signature from "Aptly Tester (don't use it) <test@aptly.info>"
|
gpgv: Good signature from "Aptly Tester (don't use it) <test@aptly.info>"
|
||||||
Loading repository unstable for changes file hardlink_0.2.1_amd64.changes...
|
Loading repository unstable for changes file hardlink_0.2.1_amd64.changes...
|
||||||
[!] changes file skipped due to uploaders config: hardlink_0.2.1_amd64.changes, keys []utils.GpgKey{"21DBB89C16DB3E6D"}: denied as no rule matches
|
[!] changes file skipped due to uploaders config: hardlink_0.2.1_amd64.changes, keys []pgp.Key{"21DBB89C16DB3E6D"}: denied as no rule matches
|
||||||
[!] Some files were skipped due to errors:
|
[!] Some files were skipped due to errors:
|
||||||
/hardlink_0.2.1_amd64.changes
|
/hardlink_0.2.1_amd64.changes
|
||||||
ERROR: some files failed to be added
|
ERROR: some files failed to be added
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
gpgv: DSA key ID 16DB3E6D
|
gpgv: DSA key ID 16DB3E6D
|
||||||
gpgv: Good signature from "Aptly Tester (don't use it) <test@aptly.info>"
|
gpgv: Good signature from "Aptly Tester (don't use it) <test@aptly.info>"
|
||||||
Loading repository unstable for changes file hardlink_0.2.1_amd64.changes...
|
Loading repository unstable for changes file hardlink_0.2.1_amd64.changes...
|
||||||
[!] changes file skipped due to uploaders config: hardlink_0.2.1_amd64.changes, keys []utils.GpgKey{"21DBB89C16DB3E6D"}: denied as no rule matches
|
[!] changes file skipped due to uploaders config: hardlink_0.2.1_amd64.changes, keys []pgp.Key{"21DBB89C16DB3E6D"}: denied as no rule matches
|
||||||
[!] Some files were skipped due to errors:
|
[!] Some files were skipped due to errors:
|
||||||
/hardlink_0.2.1_amd64.changes
|
/hardlink_0.2.1_amd64.changes
|
||||||
ERROR: some files failed to be added
|
ERROR: some files failed to be added
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
. "gopkg.in/check.v1"
|
|
||||||
)
|
|
||||||
|
|
||||||
type GpgSuite struct{}
|
|
||||||
|
|
||||||
var _ = Suite(&GpgSuite{})
|
|
||||||
|
|
||||||
func (s *GpgSuite) TestGpgKeyMatch(c *C) {
|
|
||||||
c.Check(GpgKey("EC4B033C70096AD1").Matches(GpgKey("EC4B033C70096AD1")), Equals, true)
|
|
||||||
c.Check(GpgKey("37E1C17570096AD1").Matches(GpgKey("EC4B033C70096AD1")), Equals, false)
|
|
||||||
|
|
||||||
c.Check(GpgKey("70096AD1").Matches(GpgKey("70096AD1")), Equals, true)
|
|
||||||
c.Check(GpgKey("70096AD1").Matches(GpgKey("EC4B033C")), Equals, false)
|
|
||||||
|
|
||||||
c.Check(GpgKey("37E1C17570096AD1").Matches(GpgKey("70096AD1")), Equals, true)
|
|
||||||
c.Check(GpgKey("70096AD1").Matches(GpgKey("EC4B033C70096AD1")), Equals, true)
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user