Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17cfd72173
|
||
|
|
85e33bbe90
|
||
|
|
2ec42dd61c
|
@@ -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
@@ -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")
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
@@ -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)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user