Fetching mirror (Release files) with crypto signatures.

This commit is contained in:
Andrey Smirnov
2014-02-06 22:12:31 +04:00
parent a9c812a1b3
commit 7cbba33fe7
2 changed files with 110 additions and 14 deletions
+54 -9
View File
@@ -10,6 +10,7 @@ import (
"github.com/ugorji/go/codec" "github.com/ugorji/go/codec"
"log" "log"
"net/url" "net/url"
"os"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@@ -86,10 +87,9 @@ func (repo *RemoteRepo) RefList() *PackageRefList {
return repo.packageRefs return repo.packageRefs
} }
// ReleaseURL returns URL to Release file in repo root // ReleaseURL returns URL to Release* files in repo root
// TODO: InRelease, Release.gz, Release.bz2 handling func (repo *RemoteRepo) ReleaseURL(name string) *url.URL {
func (repo *RemoteRepo) ReleaseURL() *url.URL { path := &url.URL{Path: fmt.Sprintf("dists/%s/%s", repo.Distribution, name)}
path := &url.URL{Path: fmt.Sprintf("dists/%s/Release", repo.Distribution)}
return repo.archiveRootURL.ResolveReference(path) return repo.archiveRootURL.ResolveReference(path)
} }
@@ -108,12 +108,57 @@ func (repo *RemoteRepo) PackageURL(filename string) *url.URL {
} }
// Fetch updates information about repository // Fetch updates information about repository
func (repo *RemoteRepo) Fetch(d utils.Downloader) error { func (repo *RemoteRepo) Fetch(d utils.Downloader, verifier utils.Verifier) error {
// Download release file to temporary URL var (
release, err := utils.DownloadTemp(d, repo.ReleaseURL().String()) release *os.File
if err != nil { err error
return err )
if verifier == nil {
// 0. Just download release file to temporary URL
release, err = utils.DownloadTemp(d, repo.ReleaseURL("Release").String())
if err != nil {
return err
}
} else {
// 1. try InRelease file
inrelease, err := utils.DownloadTemp(d, repo.ReleaseURL("InRelease").String())
if err != nil {
goto splitsignature
}
defer inrelease.Close()
release, err = verifier.VerifyClearsigned(inrelease)
if err != nil {
goto splitsignature
}
goto ok
splitsignature:
// 2. try Release + Release.gpg
release, err = utils.DownloadTemp(d, repo.ReleaseURL("Release").String())
if err != nil {
return err
}
releasesig, err := utils.DownloadTemp(d, repo.ReleaseURL("Release.gpg").String())
if err != nil {
return err
}
err = verifier.VerifyDetachedSignature(releasesig, release)
if err != nil {
return err
}
_, err = release.Seek(0, 0)
if err != nil {
return err
}
} }
ok:
defer release.Close() defer release.Close()
sreader := NewControlFileReader(release) sreader := NewControlFileReader(release)
+56 -5
View File
@@ -4,7 +4,10 @@ import (
"errors" "errors"
"github.com/smira/aptly/database" "github.com/smira/aptly/database"
"github.com/smira/aptly/utils" "github.com/smira/aptly/utils"
"io"
"io/ioutil"
. "launchpad.net/gocheck" . "launchpad.net/gocheck"
"os"
"testing" "testing"
) )
@@ -13,6 +16,29 @@ func Test(t *testing.T) {
TestingT(t) TestingT(t)
} }
type NullVerifier struct {
}
func (n *NullVerifier) InitKeyring() error {
return nil
}
func (n *NullVerifier) AddKeyring(keyring string) {
}
func (n *NullVerifier) VerifyDetachedSignature(signature, cleartext io.Reader) error {
return nil
}
func (n *NullVerifier) VerifyClearsigned(clearsigned io.Reader) (text *os.File, err error) {
text, _ = ioutil.TempFile("", "aptly-test")
io.Copy(text, clearsigned)
text.Seek(0, 0)
os.Remove(text.Name())
return
}
type PackageListMixinSuite struct { type PackageListMixinSuite struct {
p1, p2, p3 *Package p1, p2, p3 *Package
list *PackageList list *PackageList
@@ -78,7 +104,8 @@ func (s *RemoteRepoSuite) TestRefList(c *C) {
} }
func (s *RemoteRepoSuite) TestReleaseURL(c *C) { func (s *RemoteRepoSuite) TestReleaseURL(c *C) {
c.Assert(s.repo.ReleaseURL().String(), Equals, "http://mirror.yandex.ru/debian/dists/squeeze/Release") c.Assert(s.repo.ReleaseURL("Release").String(), Equals, "http://mirror.yandex.ru/debian/dists/squeeze/Release")
c.Assert(s.repo.ReleaseURL("InRelease").String(), Equals, "http://mirror.yandex.ru/debian/dists/squeeze/InRelease")
} }
func (s *RemoteRepoSuite) TestBinaryURL(c *C) { func (s *RemoteRepoSuite) TestBinaryURL(c *C) {
@@ -91,7 +118,7 @@ func (s *RemoteRepoSuite) TestPackageURL(c *C) {
} }
func (s *RemoteRepoSuite) TestFetch(c *C) { func (s *RemoteRepoSuite) TestFetch(c *C) {
err := s.repo.Fetch(s.downloader) err := s.repo.Fetch(s.downloader, nil)
c.Assert(err, IsNil) c.Assert(err, IsNil)
c.Assert(s.repo.Architectures, DeepEquals, []string{"amd64", "armel", "armhf", "i386", "powerpc"}) c.Assert(s.repo.Architectures, DeepEquals, []string{"amd64", "armel", "armhf", "i386", "powerpc"})
c.Assert(s.repo.Components, DeepEquals, []string{"main"}) c.Assert(s.repo.Components, DeepEquals, []string{"main"})
@@ -106,15 +133,39 @@ func (s *RemoteRepoSuite) TestFetch(c *C) {
SHA256: "377890a26f99db55e117dfc691972dcbbb7d8be1630c8fc8297530c205377f2b"}) SHA256: "377890a26f99db55e117dfc691972dcbbb7d8be1630c8fc8297530c205377f2b"})
} }
func (s *RemoteRepoSuite) TestFetchNullVerifier1(c *C) {
downloader := utils.NewFakeDownloader()
downloader.ExpectError("http://mirror.yandex.ru/debian/dists/squeeze/InRelease", errors.New("404"))
downloader.ExpectResponse("http://mirror.yandex.ru/debian/dists/squeeze/Release", exampleReleaseFile)
downloader.ExpectResponse("http://mirror.yandex.ru/debian/dists/squeeze/Release.gpg", "GPG")
err := s.repo.Fetch(downloader, &NullVerifier{})
c.Assert(err, IsNil)
c.Assert(s.repo.Architectures, DeepEquals, []string{"amd64", "armel", "armhf", "i386", "powerpc"})
c.Assert(s.repo.Components, DeepEquals, []string{"main"})
c.Assert(downloader.Empty(), Equals, true)
}
func (s *RemoteRepoSuite) TestFetchNullVerifier2(c *C) {
downloader := utils.NewFakeDownloader()
downloader.ExpectResponse("http://mirror.yandex.ru/debian/dists/squeeze/InRelease", exampleReleaseFile)
err := s.repo.Fetch(downloader, &NullVerifier{})
c.Assert(err, IsNil)
c.Assert(s.repo.Architectures, DeepEquals, []string{"amd64", "armel", "armhf", "i386", "powerpc"})
c.Assert(s.repo.Components, DeepEquals, []string{"main"})
c.Assert(downloader.Empty(), Equals, true)
}
func (s *RemoteRepoSuite) TestFetchWrongArchitecture(c *C) { func (s *RemoteRepoSuite) TestFetchWrongArchitecture(c *C) {
s.repo, _ = NewRemoteRepo("s", "http://mirror.yandex.ru/debian/", "squeeze", []string{"main"}, []string{"xyz"}) s.repo, _ = NewRemoteRepo("s", "http://mirror.yandex.ru/debian/", "squeeze", []string{"main"}, []string{"xyz"})
err := s.repo.Fetch(s.downloader) err := s.repo.Fetch(s.downloader, nil)
c.Assert(err, ErrorMatches, "architecture xyz not available in repo.*") c.Assert(err, ErrorMatches, "architecture xyz not available in repo.*")
} }
func (s *RemoteRepoSuite) TestFetchWrongComponent(c *C) { func (s *RemoteRepoSuite) TestFetchWrongComponent(c *C) {
s.repo, _ = NewRemoteRepo("s", "http://mirror.yandex.ru/debian/", "squeeze", []string{"xyz"}, []string{"i386"}) s.repo, _ = NewRemoteRepo("s", "http://mirror.yandex.ru/debian/", "squeeze", []string{"xyz"}, []string{"i386"})
err := s.repo.Fetch(s.downloader) err := s.repo.Fetch(s.downloader, nil)
c.Assert(err, ErrorMatches, "component xyz not available in repo.*") c.Assert(err, ErrorMatches, "component xyz not available in repo.*")
} }
@@ -141,7 +192,7 @@ func (s *RemoteRepoSuite) TestRefKey(c *C) {
func (s *RemoteRepoSuite) TestDownload(c *C) { func (s *RemoteRepoSuite) TestDownload(c *C) {
s.repo.Architectures = []string{"i386"} s.repo.Architectures = []string{"i386"}
err := s.repo.Fetch(s.downloader) err := s.repo.Fetch(s.downloader, nil)
c.Assert(err, IsNil) c.Assert(err, IsNil)
s.downloader.ExpectError("http://mirror.yandex.ru/debian/dists/squeeze/main/binary-i386/Packages.bz2", errors.New("HTTP 404")) s.downloader.ExpectError("http://mirror.yandex.ru/debian/dists/squeeze/main/binary-i386/Packages.bz2", errors.New("HTTP 404"))