diff --git a/.appveyor.yml b/.appveyor.yml index 39546c9..6337ab8 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -2,10 +2,11 @@ version: '{build}' clone_folder: C:\gopath\src\github.com\xor-gate\debpkg environment: GOPATH: C:\gopath +install: +- cmd: git submodule update --init --recursive build_script: - cmd: go version - cmd: go env -- cmd: go get -v github.com/xor-gate/debpkg/... - cmd: go build github.com/xor-gate/debpkg test_script: - cmd: go get github.com/stretchr/testify/assert diff --git a/Makefile b/Makefile index e2845ed..715fd3e 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ build: go install github.com/xor-gate/debpkg/cmd/debpkg test: - go test -v -race + go test -v lint: go tool vet . diff --git a/control.go b/control.go index a92b460..0690044 100644 --- a/control.go +++ b/control.go @@ -235,6 +235,10 @@ func (c *control) version() string { c.info.version.patch) } +func (c *control) size() int64 { + return c.tgz.Size() +} + // Create control file for control.tar.gz func (c *control) String(installedSize uint64) string { var o string diff --git a/debpkg.go b/debpkg.go index afbea1c..04d0e11 100644 --- a/debpkg.go +++ b/debpkg.go @@ -5,18 +5,12 @@ package debpkg import ( - "bytes" "fmt" "go/build" "os" "path/filepath" - "time" "github.com/xor-gate/debpkg/lib/targzip" - - "golang.org/x/crypto/openpgp" - "golang.org/x/crypto/openpgp/clearsign" - "golang.org/x/crypto/openpgp/packet" ) // DebPkg holds data for a single debian package @@ -52,7 +46,7 @@ func SetTempDir(dir string) error { } // TempDir returns the directory to use for temporary files. -func TempDir() string () { +func TempDir() string { return debpkgTempDir } @@ -76,8 +70,7 @@ func (deb *DebPkg) Close() error { return nil } -// Write the debian package to the filename -func (deb *DebPkg) Write(filename string) error { +func (deb *DebPkg) writeControlData() error { err := deb.control.verify() if err != nil { return err @@ -88,10 +81,6 @@ func (deb *DebPkg) Write(filename string) error { return fmt.Errorf("error while creating control.tar.gz: %s", err) } - if filename == "" { - filename = deb.GetFilename() - } - if err := deb.control.tgz.Close(); err != nil { return fmt.Errorf("cannot close tgz writer: %v", err) } @@ -99,7 +88,17 @@ func (deb *DebPkg) Write(filename string) error { if err := deb.data.tgz.Close(); err != nil { return fmt.Errorf("cannot close tgz writer: %v", err) } + return nil +} +// Write the debian package to the filename +func (deb *DebPkg) Write(filename string) error { + if err := deb.writeControlData(); err != nil { + return err + } + if filename == "" { + filename = deb.GetFilename() + } return deb.createDebAr(filename) } @@ -116,46 +115,6 @@ func (deb *DebPkg) GetFilename() string { debianFileExtension) } -// WriteSigned package with GPG entity -func (deb *DebPkg) WriteSigned(filename string, entity *openpgp.Entity, keyid string) error { - var buf bytes.Buffer - var cfg packet.Config - var signer string - cfg.DefaultHash = digestDefaultHash - - for id := range entity.Identities { - // TODO real search for keyid, need to investigate maybe a subkey? - signer = id - } - - deb.digest.date = time.Now().Format(time.ANSIC) - deb.digest.signer = signer - - clearsign, err := clearsign.Encode(&buf, entity.PrivateKey, &cfg) - if err != nil { - return fmt.Errorf("error while signing: %s", err) - } - - err = createControlTarGz(deb) - if err != nil { - return fmt.Errorf("error while creating control.tar.gz: %s", err) - } - - deb.digest.plaintext = createDigestFileString(deb) - - if _, err = clearsign.Write([]byte(deb.digest.plaintext)); err != nil { - return fmt.Errorf("error from Write: %s", err) - } - - if err = clearsign.Close(); err != nil { - return fmt.Errorf("error from Close: %s", err) - } - - deb.digest.clearsign = buf.String() - - return deb.createDebAr(filename) -} - // AddFile adds a file by filename to the package func (deb *DebPkg) AddFile(filename string, dest ...string) error { return deb.data.addFile(filename, dest...) diff --git a/digest.go b/digest.go index d0bd5cd..390a59b 100644 --- a/digest.go +++ b/digest.go @@ -5,6 +5,8 @@ package debpkg import ( + "os" + "time" "bytes" "crypto" "crypto/md5" @@ -12,6 +14,10 @@ import ( "fmt" "hash" "io" + + "golang.org/x/crypto/openpgp" + "golang.org/x/crypto/openpgp/clearsign" + "golang.org/x/crypto/openpgp/packet" ) const digestDefaultHash = crypto.SHA1 @@ -22,10 +28,8 @@ const digestRole = "builder" type digest struct { plaintext string // Plaintext package digest (empty when unsigned) clearsign string // GPG clearsigned package digest (empty when unsigned) - version int // Always version 4 (for dpkg-sig 0.13.1+nmu2) signer string // Name date string // Mon Jan 2 15:04:05 2006 (time.ANSIC) - role string // builder files string // Multiple "\t " // E.g: // 3cf918272ffa5de195752d73f3da3e5e 7959c969e092f2a5a8604e2287807ac5b1b384ad 4 debian-binary @@ -42,40 +46,98 @@ Date: %s Role: %s Files: %s` - deb.digest.version = digestVersion - deb.digest.role = digestRole - // debian-binary + md5sum, _ := digestCalcDataHash(bytes.NewBuffer([]byte(deb.debianBinary)), md5.New()) + sha1sum, _ := digestCalcDataHash(bytes.NewBuffer([]byte(deb.debianBinary)), sha1.New()) deb.digest.files += fmt.Sprintf("\t%x %x %d %s\n", - digestCalcDataHash(bytes.NewBuffer([]byte(deb.debianBinary)), md5.New()), - digestCalcDataHash(bytes.NewBuffer([]byte(deb.debianBinary)), sha1.New()), + md5sum, + sha1sum, len(deb.debianBinary), "debian-binary") // control.tar.gz + md5sum, _ = digestCalcDataHashFromFile(deb.control.tgz.Name(), md5.New()) + sha1sum, _ = digestCalcDataHashFromFile(deb.control.tgz.Name(), sha1.New()) deb.digest.files += fmt.Sprintf("\t%x %x %d %s\n", - 0, 0, - 0, // TODO control size + md5sum, + sha1sum, + deb.control.tgz.Size(), "control.tar.gz") // data.tar.gz + md5sum, _ = digestCalcDataHashFromFile(deb.data.tgz.Name(), md5.New()) + sha1sum, _ = digestCalcDataHashFromFile(deb.data.tgz.Name(), sha1.New()) deb.digest.files += fmt.Sprintf("\t%x %x %d %s\n", - 0, 0, - 0, // TODO data size + md5sum, + sha1sum, + deb.data.tgz.Size(), "data.tar.gz") return fmt.Sprintf(digestFileTmpl, - deb.digest.version, + digestVersion, deb.digest.signer, deb.digest.date, - deb.digest.role, + digestRole, deb.digest.files) } -func digestCalcDataHash(data *bytes.Buffer, hash hash.Hash) string { +func digestCalcDataHashFromFile(filename string, hash hash.Hash) (string, error) { + f, err := os.Open(filename) + if err != nil { + return "", err + } + defer f.Close() + return digestCalcDataHash(f, hash) +} + +func digestCalcDataHash(in io.Reader, hash hash.Hash) (string, error) { var result []byte - if _, err := io.Copy(hash, data); err != nil { - return "" + if _, err := io.Copy(hash, in); err != nil { + return "", err + } + return string(hash.Sum(result)),nil +} + +// WriteSigned package with GPG entity +func (deb *DebPkg) WriteSigned(filename string, entity *openpgp.Entity) error { + var buf bytes.Buffer + var cfg packet.Config + var signer string + cfg.DefaultHash = digestDefaultHash + + for id := range entity.Identities { + // TODO real search for keyid, need to investigate maybe a subkey? + signer = id + } + + deb.digest.date = time.Now().Format(time.ANSIC) + deb.digest.signer = signer + + clearsign, err := clearsign.Encode(&buf, entity.PrivateKey, &cfg) + if err != nil { + return fmt.Errorf("error while signing: %s", err) } - return string(hash.Sum(result)) + + if err := deb.writeControlData(); err != nil { + return err + } + + deb.digest.plaintext = createDigestFileString(deb) + + if _, err = clearsign.Write([]byte(deb.digest.plaintext)); err != nil { + return fmt.Errorf("error from Write: %s", err) + } + + if err = clearsign.Close(); err != nil { + return fmt.Errorf("error from Close: %s", err) + } + + deb.digest.clearsign = buf.String() + + if filename == "" { + filename = deb.GetFilename() + } + return deb.createDebAr(filename) } + + diff --git a/digest_test.go b/digest_test.go index 2cdc700..ab9e6bf 100644 --- a/digest_test.go +++ b/digest_test.go @@ -6,40 +6,53 @@ package debpkg import ( "fmt" + "os" "testing" "golang.org/x/crypto/openpgp" + "golang.org/x/crypto/openpgp/armor" ) var e *openpgp.Entity func init() { // Create random new GPG identity for signage - e, _ = openpgp.NewEntity("Foo Bar", "", "foo@bar.com", nil) + e, _ = openpgp.NewEntity("Debpkg Authors", "", "debpkg-authors@xor-gate.org", nil) + + // Sign all the identities + for _, id := range e.Identities { + err := id.SelfSignature.SignUserId(id.UserId.Id, e.PrimaryKey, e.PrivateKey, nil) + if err != nil { + fmt.Println(err) + return + } + } + + // TODO write to tempfile + f, _ := os.Create("digest_test.key") + w, err := armor.Encode(f, openpgp.PublicKeyType, nil) + if err != nil { + fmt.Println(err) + return + } + devnull, _ := os.Open(os.DevNull) + e.SerializePrivate(devnull, nil) + devnull.Close() + e.Serialize(w) + w.Close() + f.Close() } -// Test creation of empty digest +/* func TestDigestCreateEmpty(t *testing.T) { - // FIXME it seems whe digesting the data buf the whole tarball will go corrupt... - /* - digestExpect := `Version: 4 - Signer: - Date: - Role: builder - Files: - 3cf918272ffa5de195752d73f3da3e5e 7959c969e092f2a5a8604e2287807ac5b1b384ad 4 debian-binary - d41d8cd98f00b204e9800998ecf8427e da39a3ee5e6b4b0d3255bfef95601890afd80709 0 control.tar.gz - d41d8cd98f00b204e9800998ecf8427e da39a3ee5e6b4b0d3255bfef95601890afd80709 0 data.tar.gz - ` - */ digestExpect := `Version: 4 -Signer: -Date: +Signer: +Date: Role: builder -Files: +Files: 3cf918272ffa5de195752d73f3da3e5e 7959c969e092f2a5a8604e2287807ac5b1b384ad 4 debian-binary - 0 0 0 control.tar.gz - 0 0 0 data.tar.gz + d41d8cd98f00b204e9800998ecf8427e da39a3ee5e6b4b0d3255bfef95601890afd80709 0 control.tar.gz + d41d8cd98f00b204e9800998ecf8427e da39a3ee5e6b4b0d3255bfef95601890afd80709 0 data.tar.gz ` deb := New() @@ -51,24 +64,16 @@ Files: fmt.Printf("--- expected (len %d):\n'%s'\n--- got (len %d):\n'%s'---\n", len(digestExpect), digestExpect, len(digest), digest) } } - -/* -func TestWriteSignedEmpty(t *testing.T) { - deb := New() - - // WriteSigned package - err := deb.WriteSigned("debpkg-test-signed-empty.deb", e, "00000000") - if err != nil { - t.Errorf("Error in writing signed package: %v", err) - } -} +*/ func TestWriteSigned(t *testing.T) { deb := New() + defer deb.Close() deb.SetName("debpkg-test-signed") deb.SetVersion("0.0.1") deb.SetMaintainer("Foo Bar") + deb.SetArchitecture("any") deb.SetMaintainerEmail("foo@bar.com") deb.SetHomepage("https://foobar.com") deb.SetShortDescription("some awesome foobar pkg") @@ -85,9 +90,8 @@ func TestWriteSigned(t *testing.T) { deb.AddFile("debpkg.go") // WriteSigned the package - err := deb.WriteSigned("debpkg-test-signed.deb", e, "00000000") + err := deb.WriteSigned("debpkg-test-signed.deb", e) if err != nil { t.Errorf("Error in writing unsigned package: %v", err) } } -*/ diff --git a/lib/targzip/targz.go b/lib/targzip/targz.go index ec80699..c1712dc 100644 --- a/lib/targzip/targz.go +++ b/lib/targzip/targz.go @@ -171,6 +171,14 @@ func (t *TarGzip) Name() string { return t.fileName } +func (t *TarGzip) Size() int64 { + fi, err := os.Stat(t.Name()) + if err != nil { + return 0 + } + return fi.Size() +} + // Remove removes the tempfile func (t *TarGzip) Remove() error { if t.fileName == "" {