3 Commits
Author SHA1 Message Date
sm 17cfd72173 Stub out fetching secret key entity 2018-02-26 20:07:47 -08:00
sm 85e33bbe90 Simple pre-flight checks
More of this to come ...
2018-02-26 20:02:23 -08:00
sm 2ec42dd61c Stub out pm package create 2018-02-26 19:58:28 -08:00
4 changed files with 72 additions and 110 deletions
+29
View File
@@ -6,6 +6,7 @@ import (
"os" "os"
"mcquay.me/pm/keyring" "mcquay.me/pm/keyring"
"mcquay.me/pm/pkg"
) )
const usage = `pm: simple, cross-platform system package manager const usage = `pm: simple, cross-platform system package manager
@@ -13,6 +14,7 @@ const usage = `pm: simple, cross-platform system package manager
subcommands: subcommands:
environ (env) -- print environment information environ (env) -- print environment information
keyring (key) -- interact with pm's OpenPGP keyring keyring (key) -- interact with pm's OpenPGP keyring
package (pkg) -- create packages
` `
const keyUsage = `pm keyring: interact with pm's OpenPGP keyring const keyUsage = `pm keyring: interact with pm's OpenPGP keyring
@@ -27,6 +29,12 @@ subcommands:
verify (v) -- verify a detached signature verify (v) -- verify a detached signature
` `
const pkgUsage = `pm package: generate pm-compatible packages
subcommands:
create (c) -- create a fresh keypair
`
func main() { func main() {
if len(os.Args) < 2 { if len(os.Args) < 2 {
fatalf("pm: missing subcommand\n\n%v", usage) fatalf("pm: missing subcommand\n\n%v", usage)
@@ -126,6 +134,27 @@ func main() {
default: default:
fatalf("unknown keyring subcommand: %q\n\nusage: %v", sub, keyUsage) fatalf("unknown keyring subcommand: %q\n\nusage: %v", sub, keyUsage)
} }
case "package", "pkg":
if len(os.Args[1:]) < 2 {
fatalf("pm package: insufficient args\n\nusage: %v", pkgUsage)
}
sub := os.Args[2]
switch sub {
case "create", "creat", "c":
if signID == "" {
fatalf("must set PM_PGP_ID\n")
}
args := os.Args[3:]
if len(args) != 1 {
fatalf("usage: pm package create <directory>\n")
}
dir := args[0]
if err := pkg.Create(root, signID, dir); err != nil {
fatalf("creating package: %v\n", err)
}
default:
fatalf("unknown package subcommand: %q\n\nusage: %v", sub, pkgUsage)
}
default: default:
fatalf("uknown subcommand %q\n\nusage: %v", cmd, usage) fatalf("uknown subcommand %q\n\nusage: %v", cmd, usage)
} }
+17 -20
View File
@@ -78,8 +78,8 @@ func NewKeyPair(root, name, email string) error {
// ListKeys prints keyring information to w. // ListKeys prints keyring information to w.
func ListKeys(root string, w io.Writer) error { func ListKeys(root string, w io.Writer) error {
if err := checkDir(root); err != nil { if err := ensureDir(root); err != nil {
return errors.Wrap(err, "can't find pgp dir") return errors.Wrap(err, "can't find or create pgp dir")
} }
srn, prn := getNames(root) srn, prn := getNames(root)
secs, pubs, err := getELs(srn, prn) secs, pubs, err := getELs(srn, prn)
@@ -105,8 +105,8 @@ func ListKeys(root string, w io.Writer) error {
// Export prints pubkey information associated with email to w. // Export prints pubkey information associated with email to w.
func Export(root string, w io.Writer, email string) error { func Export(root string, w io.Writer, email string) error {
if err := checkDir(root); err != nil { if err := ensureDir(root); err != nil {
return errors.Wrap(err, "can't find pgp dir") return errors.Wrap(err, "can't find or create pgp dir")
} }
srn, prn := getNames(root) srn, prn := getNames(root)
_, pubs, err := getELs(srn, prn) _, pubs, err := getELs(srn, prn)
@@ -142,8 +142,8 @@ func Import(root string, w io.Reader) error {
return errors.Wrap(err, "reading keyring") return errors.Wrap(err, "reading keyring")
} }
if err := checkDir(root); err != nil { if err := ensureDir(root); err != nil {
return errors.Wrap(err, "can't find pgp dir") return errors.Wrap(err, "can't find or create pgp dir")
} }
srn, prn := getNames(root) srn, prn := getNames(root)
_, pubs, err := getELs(srn, prn) _, pubs, err := getELs(srn, prn)
@@ -185,8 +185,8 @@ func Import(root string, w io.Reader) error {
// Sign takes an id and a reader and writes the signature for that id to sig. // Sign takes an id and a reader and writes the signature for that id to sig.
func Sign(root, id string, in io.Reader, sig io.Writer) error { func Sign(root, id string, in io.Reader, sig io.Writer) error {
if err := checkDir(root); err != nil { if err := ensureDir(root); err != nil {
return errors.Wrap(err, "can't find pgp dir") return errors.Wrap(err, "can't find or create pgp dir")
} }
srn, prn := getNames(root) srn, prn := getNames(root)
secs, _, err := getELs(srn, prn) secs, _, err := getELs(srn, prn)
@@ -206,8 +206,8 @@ func Sign(root, id string, in io.Reader, sig io.Writer) error {
// Verify verifies a file's deatched signature. // Verify verifies a file's deatched signature.
func Verify(root string, file, sig io.Reader) error { func Verify(root string, file, sig io.Reader) error {
if err := checkDir(root); err != nil { if err := ensureDir(root); err != nil {
return errors.Wrap(err, "can't find pgp dir") return errors.Wrap(err, "can't find or create pgp dir")
} }
srn, prn := getNames(root) srn, prn := getNames(root)
_, pubs, err := getELs(srn, prn) _, pubs, err := getELs(srn, prn)
@@ -225,8 +225,8 @@ func Verify(root string, file, sig io.Reader) error {
// It skips public keys that have matching secret keys, and does not effect // It skips public keys that have matching secret keys, and does not effect
// private keys. // private keys.
func Remove(root string, id string) error { func Remove(root string, id string) error {
if err := checkDir(root); err != nil { if err := ensureDir(root); err != nil {
return errors.Wrap(err, "can't find pgp dir") return errors.Wrap(err, "can't find or create pgp dir")
} }
srn, prn := getNames(root) srn, prn := getNames(root)
secs, pubs, err := getELs(srn, prn) secs, pubs, err := getELs(srn, prn)
@@ -266,14 +266,6 @@ func pGPDir(root string) string {
return filepath.Join(root, "var", "lib", "pm", "pgp") return filepath.Join(root, "var", "lib", "pm", "pgp")
} }
func checkDir(root string) error {
d := pGPDir(root)
if !fs.Exists(d) {
return fmt.Errorf("pgp dir does not exist")
}
return nil
}
func ensureDir(root string) error { func ensureDir(root string) error {
d := pGPDir(root) d := pGPDir(root)
if !fs.Exists(d) { if !fs.Exists(d) {
@@ -348,3 +340,8 @@ func findKey(el openpgp.EntityList, id string) (*openpgp.Entity, error) {
} }
return e, fmt.Errorf("key %q not found", id) return e, fmt.Errorf("key %q not found", id)
} }
// FindSecretEntity searches for id in the secret keyring.
func FindSecretEntity(root, id string) (*openpgp.Entity, error) {
return nil, errors.New("NYI")
}
-90
View File
@@ -1,90 +0,0 @@
package keyring
import (
"bytes"
"io/ioutil"
"os"
"regexp"
"testing"
)
const (
ExpectedListKeysRegex = "sec: [[:alnum:]]{8}:[[:space:]]*foo[[:space:]]*\\(pm\\)[[:space:]]*<bar>\npub: [[:alnum:]]{8}:[[:space:]]*foo[[:space:]]*\\(pm\\)[[:space:]]*<bar>"
)
func TestNewKeyPair(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatalf("Couldn't create tmpdir")
}
defer os.RemoveAll(tmpdir)
var newKeyPair = []struct {
r, n, e string
expected bool
}{
{"", "", "", false},
{"", "foo", "", false},
{"", "foo", "bad<>email", false},
{tmpdir, "foo", "bar", true},
}
for _, rt := range newKeyPair {
actual := NewKeyPair(rt.r, rt.n, rt.e)
if (actual == nil) != rt.expected {
t.Errorf(
"failed NewKeyPair with an error: %v\n\troot: %s\n\tname: %s\n\temail:%s\n\texpected: %t\n\t actual: %t",
actual,
rt.r,
rt.n,
rt.e,
(actual == nil),
rt.expected,
)
}
}
}
func TestListKeys(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatalf("Couldn't create tmpdir")
}
defer os.RemoveAll(tmpdir)
err = NewKeyPair(tmpdir, "foo", "bar")
if err != nil {
t.Fatalf("Couldn't create New Key Pair")
}
var newKeyPair = []struct {
r string
regex string
w *bytes.Buffer
expected bool
}{
{"", "", bytes.NewBuffer(nil), false},
{tmpdir, ExpectedListKeysRegex, bytes.NewBuffer(nil), true},
}
for _, rt := range newKeyPair {
actual := ListKeys(rt.r, rt.w)
if (actual == nil) != rt.expected {
t.Errorf(
"failed ListKeys with an error: %v\n\troot: %s\n\texpected: %t\n\t actual: %t",
actual,
rt.r,
(actual == nil),
rt.expected,
)
}
if rt.expected {
matched, err := regexp.MatchString(rt.regex, rt.w.String())
if err != nil {
t.Fatalf("error%v, ", err)
}
if !matched {
t.Errorf("did not match")
t.Errorf("ListKeys did not match expected regex; wanted: [%q], got: [%s]", rt.regex, rt.w.String())
}
}
}
}
+26
View File
@@ -0,0 +1,26 @@
package pkg
import (
"fmt"
"log"
"github.com/pkg/errors"
"mcquay.me/fs"
"mcquay.me/pm/keyring"
)
// Create traverses the contents of dir and emits a valid pkg, signed by id
func Create(root, id, dir string) error {
if !fs.Exists(dir) {
return fmt.Errorf("%q: doesn't exist", dir)
}
if !fs.IsDir(dir) {
return fmt.Errorf("%q: is not a directory", dir)
}
e, err := keyring.FindSecretEntity(dir, id)
if err != nil {
return errors.Wrap(err, "find secret key")
}
log.Printf("found key: %v", e.PrimaryKey.KeyIdShortString())
return fmt.Errorf("creating package from %q for %q: NYI", dir, id)
}