1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package app
17
18 import (
19 "encoding/base64"
20 "errors"
21 "fmt"
22 "net/url"
23 "strings"
24
25 "github.com/sigstore/rekor/pkg/pki"
26 "github.com/sigstore/rekor/pkg/types"
27 "github.com/spf13/cobra"
28 "github.com/spf13/viper"
29 )
30
31
32 func addFlagToCmd(cmd *cobra.Command, required bool, flagType FlagType, flag, desc string) error {
33 cmd.Flags().Var(NewFlagValue(flagType, ""), flag, desc)
34 if required {
35 return cmd.MarkFlagRequired(flag)
36 }
37 return nil
38 }
39
40
41 func addLogIndexFlag(cmd *cobra.Command, required bool) error {
42 return addFlagToCmd(cmd, required, logIndexFlag, "log-index", "the index of the entry in the transparency log")
43 }
44
45
46 func addUUIDPFlags(cmd *cobra.Command, required bool) error {
47 return addFlagToCmd(cmd, required, uuidFlag, "uuid", "UUID of entry in transparency log (if known)")
48 }
49
50 func addArtifactPFlags(cmd *cobra.Command) error {
51 flags := map[string]struct {
52 flagType FlagType
53 desc string
54 required bool
55 }{
56 "signature": {
57 fileOrURLFlag,
58 "path or URL to detached signature file",
59 false,
60 },
61 "type": {
62 typeFlag,
63 fmt.Sprintf("type of entry expressed as type(:version)?; supported types = %v", types.ListImplementedTypes()),
64 false,
65 },
66 "pki-format": {
67 pkiFormatFlag,
68 fmt.Sprintf("format of the signature and/or public key; options = %v", pki.SupportedFormats()),
69 false,
70 },
71 "public-key": {
72 multiFileOrURLFlag,
73 "path or URL to public key file",
74 false,
75 },
76 "artifact": {
77 fileOrURLFlag,
78 "path or URL to artifact file",
79 false,
80 },
81 "artifact-hash": {
82 shaFlag,
83 "hex encoded SHA256 hash of artifact (when using URL)",
84 false,
85 },
86 "entry": {
87 fileOrURLFlag,
88 "path or URL to pre-formatted entry file",
89 false,
90 },
91 "aad": {
92 base64Flag,
93 "base64 encoded additional authenticated data",
94 false,
95 },
96 }
97
98 for flag, flagVal := range flags {
99 if err := addFlagToCmd(cmd, flagVal.required, flagVal.flagType, flag, flagVal.desc); err != nil {
100 return err
101 }
102 }
103
104 return nil
105 }
106
107 func validateArtifactPFlags(uuidValid, indexValid bool) error {
108 uuidGiven := false
109 if uuidValid && viper.GetString("uuid") != "" {
110 uuidGiven = true
111 }
112 indexGiven := false
113 if indexValid && viper.GetString("log-index") != "" {
114 indexGiven = true
115 }
116
117
118 if viper.GetString("entry") == "" && viper.GetString("artifact") == "" && viper.GetString("artifact-hash") == "" {
119 if (uuidGiven && uuidValid) || (indexGiven && indexValid) {
120 return nil
121 }
122 return errors.New("either 'entry' or 'artifact' or 'artifact-hash' must be specified")
123 }
124
125 return nil
126 }
127
128 func CreatePropsFromPflags() *types.ArtifactProperties {
129 props := &types.ArtifactProperties{}
130
131 artifactString := viper.GetString("artifact")
132 if artifactString != "" {
133 if isURL(artifactString) {
134 props.ArtifactPath, _ = url.Parse(artifactString)
135 } else {
136 props.ArtifactPath = &url.URL{Path: artifactString}
137 }
138 }
139
140 props.ArtifactHash = viper.GetString("artifact-hash")
141
142 signatureString := viper.GetString("signature")
143 if signatureString != "" {
144 if isURL(signatureString) {
145 props.SignaturePath, _ = url.Parse(signatureString)
146 } else {
147 props.SignaturePath = &url.URL{Path: signatureString}
148 }
149 }
150
151 publicKeyString := viper.GetString("public-key")
152 splitPubKeyString := strings.Split(publicKeyString, ",")
153 if len(splitPubKeyString) > 0 {
154 collectedKeys := []*url.URL{}
155 for _, key := range splitPubKeyString {
156 if isURL(key) {
157 keyPath, _ := url.Parse(key)
158 collectedKeys = append(collectedKeys, keyPath)
159 } else {
160 collectedKeys = append(collectedKeys, &url.URL{Path: key})
161 }
162 }
163 props.PublicKeyPaths = collectedKeys
164 }
165
166 props.PKIFormat = viper.GetString("pki-format")
167 b64aad := viper.GetString("aad")
168 if b64aad != "" {
169 props.AdditionalAuthenticatedData, _ = base64.StdEncoding.DecodeString(b64aad)
170 }
171
172 return props
173 }
174
175
176 func ParseTypeFlag(typeStr string) (string, string, error) {
177
178
179
180
181 typeStrings := strings.SplitN(typeStr, ":", 2)
182 tf, ok := types.TypeMap.Load(typeStrings[0])
183 if !ok {
184 return "", "", fmt.Errorf("unknown type %v", typeStrings[0])
185 }
186 ti := tf.(func() types.TypeImpl)()
187 if ti == nil {
188 return "", "", fmt.Errorf("type %v is not implemented", typeStrings[0])
189 }
190
191 switch len(typeStrings) {
192 case 1:
193 return typeStrings[0], "", nil
194 case 2:
195 if !ti.IsSupportedVersion(typeStrings[1]) {
196 return "", "", fmt.Errorf("type %v does not support version %v", typeStrings[0], typeStrings[1])
197 }
198 return typeStrings[0], typeStrings[1], nil
199 }
200 return "", "", errors.New("malformed type string")
201 }
202
View as plain text