This repository has been archived by the owner on Jan 9, 2020. It is now read-only.
forked from juju/juju
/
signmetadata.go
108 lines (96 loc) · 3.09 KB
/
signmetadata.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.
package main
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/juju/cmd"
"github.com/juju/loggo"
"launchpad.net/gnuflag"
"github.com/juju/juju/environs/simplestreams"
)
var signMetadataDoc = `
sign searches for json files in the specified directory tree and inline signs
them using the private key in the specified keyring file. For each .json file, a
corresponding .sjson file is procduced.
The specified keyring file is expected to contain an amored private key. If the key
is encrypted, then the specified passphrase is used to decrypt the key.
`
// SignMetadataCommand is used to sign simplestreams metadata json files.
type SignMetadataCommand struct {
cmd.CommandBase
dir string
keyFile string
passphrase string
}
func (c *SignMetadataCommand) Info() *cmd.Info {
return &cmd.Info{
Name: "sign",
Purpose: "sign simplestreams metadata",
Doc: signMetadataDoc,
}
}
func (c *SignMetadataCommand) SetFlags(f *gnuflag.FlagSet) {
c.CommandBase.SetFlags(f)
f.StringVar(&c.dir, "d", "", "directory in which to look for metadata")
f.StringVar(&c.keyFile, "k", "", "file containing the amored private signing key")
f.StringVar(&c.passphrase, "p", "", "passphrase used to decrypt the private key")
}
func (c *SignMetadataCommand) Init(args []string) error {
if c.dir == "" {
return fmt.Errorf("directory must be specified")
}
if c.keyFile == "" {
return fmt.Errorf("keyfile must be specified")
}
return cmd.CheckEmpty(args)
}
func (c *SignMetadataCommand) Run(context *cmd.Context) error {
loggo.RegisterWriter("signmetadata", cmd.NewCommandLogWriter("juju.plugins.metadata", context.Stdout, context.Stderr), loggo.INFO)
defer loggo.RemoveWriter("signmetadata")
keyData, err := ioutil.ReadFile(c.keyFile)
if err != nil {
return err
}
dir := context.AbsPath(c.dir)
return process(dir, string(keyData), c.passphrase)
}
func process(dir, key, passphrase string) error {
logger.Debugf("processing directory %q", dir)
// Do any json files in dir
filenames, err := filepath.Glob(filepath.Join(dir, "*"+simplestreams.UnsignedSuffix))
if len(filenames) > 0 {
logger.Infof("signing %d file(s) in %q", len(filenames), dir)
}
for _, filename := range filenames {
logger.Infof("signing file %q", filename)
f, err := os.Open(filename)
if err != nil {
return fmt.Errorf("opening file %q: %v", filename, err)
}
encoded, err := simplestreams.Encode(f, key, passphrase)
if err != nil {
return fmt.Errorf("encoding file %q: %v", filename, err)
}
signedFilename := strings.Replace(filename, simplestreams.UnsignedSuffix, simplestreams.SignedSuffix, -1)
if err = ioutil.WriteFile(signedFilename, encoded, 0644); err != nil {
return fmt.Errorf("writing signed file %q: %v", signedFilename, err)
}
}
// Now process any directories in dir.
files, err := ioutil.ReadDir(dir)
if err != nil {
return err
}
for _, f := range files {
if f.IsDir() {
if err = process(filepath.Join(dir, f.Name()), key, passphrase); err != nil {
return err
}
}
}
return nil
}