Skip to content

Commit 6a08e97

Browse files
committed
Implement a sign-many command for better performance
1 parent 620d0b7 commit 6a08e97

1 file changed

Lines changed: 151 additions & 0 deletions

File tree

cmdline/token/signmanycmd.go

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
//
2+
// Copyright (c) SAS Institute Inc.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//
16+
17+
package token
18+
19+
import (
20+
"bytes"
21+
"context"
22+
"errors"
23+
"fmt"
24+
"os"
25+
26+
"github.com/spf13/cobra"
27+
28+
"github.com/sassoftware/relic/v7/cmdline/shared"
29+
"github.com/sassoftware/relic/v7/internal/signinit"
30+
"github.com/sassoftware/relic/v7/lib/certloader"
31+
"github.com/sassoftware/relic/v7/signers"
32+
)
33+
34+
var SignManyCmd = &cobra.Command{
35+
Use: "sign-many",
36+
Short: "Sign multiple packages using a token",
37+
RunE: signManyCmd,
38+
}
39+
40+
var (
41+
margIfUnsigned bool
42+
margSigType string
43+
margFiles []string
44+
)
45+
46+
func init() {
47+
shared.RootCmd.AddCommand(SignManyCmd)
48+
addKeyFlags(SignManyCmd)
49+
SignManyCmd.Flags().StringArrayVarP(&margFiles, "file", "f", []string{}, "Input file to sign; Can be specified multiple times")
50+
SignManyCmd.Flags().StringVarP(&argSigType, "sig-type", "T", "", "Specify signature type (default: auto-detect)")
51+
SignManyCmd.Flags().BoolVar(&argIfUnsigned, "if-unsigned", false, "Skip signing if the file already has a signature")
52+
shared.AddDigestFlag(SignManyCmd)
53+
shared.AddLateHook(func() {
54+
signers.MergeFlags(SignManyCmd)
55+
})
56+
}
57+
58+
func signFile(mod *signers.Signer, opts *signers.SignOpts, cert *certloader.Certificate, argFile string, argOutput string) error {
59+
opts.Path = argFile
60+
infile, err := shared.OpenForPatching(argFile, argOutput)
61+
if err != nil {
62+
return shared.Fail(err)
63+
} else {
64+
defer infile.Close()
65+
}
66+
if argIfUnsigned {
67+
if infile == os.Stdin {
68+
return shared.Fail(errors.New("cannot use --if-unsigned with standard input"))
69+
}
70+
if signed, err := mod.IsSigned(infile); err != nil {
71+
return shared.Fail(err)
72+
} else if signed {
73+
fmt.Fprintf(os.Stderr, "skipping already-signed file: %s\n", argFile)
74+
return nil
75+
}
76+
if _, err := infile.Seek(0, 0); err != nil {
77+
return shared.Fail(fmt.Errorf("rewinding input file: %w", err))
78+
}
79+
}
80+
// transform the input, sign the stream, and apply the result
81+
transform, err := mod.GetTransform(infile, *opts)
82+
if err != nil {
83+
return shared.Fail(err)
84+
}
85+
stream, err := transform.GetReader()
86+
if err != nil {
87+
return shared.Fail(err)
88+
}
89+
blob, err := mod.Sign(stream, cert, *opts)
90+
if err != nil {
91+
return shared.Fail(err)
92+
}
93+
mimeType := opts.Audit.GetMimeType()
94+
if err := transform.Apply(argOutput, mimeType, bytes.NewReader(blob)); err != nil {
95+
return shared.Fail(err)
96+
}
97+
// if needed, do a final fixup step
98+
if mod.Fixup != nil {
99+
f, err := os.OpenFile(argOutput, os.O_RDWR, 0)
100+
if err != nil {
101+
return shared.Fail(err)
102+
}
103+
defer f.Close()
104+
if err := mod.Fixup(f); err != nil {
105+
return shared.Fail(err)
106+
}
107+
}
108+
if err := signinit.PublishAudit(opts.Audit); err != nil {
109+
return err
110+
}
111+
fmt.Fprintln(os.Stderr, "Signed", argFile)
112+
return nil
113+
}
114+
115+
func signManyCmd(cmd *cobra.Command, args []string) error {
116+
if len(margFiles) == 0 || argKeyName == "" {
117+
return errors.New("--file and --key are required")
118+
}
119+
mod, err := signers.ByFile(margFiles[0], argSigType)
120+
if err != nil {
121+
return shared.Fail(err)
122+
}
123+
if mod.Sign == nil {
124+
return shared.Fail(fmt.Errorf("can't sign files of type: %s", mod.Name))
125+
}
126+
flags, err := mod.FlagsFromCmdline(cmd.Flags())
127+
if err != nil {
128+
return shared.Fail(err)
129+
}
130+
hash, err := shared.GetDigest()
131+
if err != nil {
132+
return shared.Fail(err)
133+
}
134+
token, err := openTokenByKey(argKeyName)
135+
if err != nil {
136+
return shared.Fail(err)
137+
}
138+
cert, opts, err := signinit.Init(context.Background(), mod, token, argKeyName, hash, flags)
139+
if err != nil {
140+
return shared.Fail(err)
141+
}
142+
143+
for _, file := range margFiles {
144+
err := signFile(mod, opts, cert, file, file)
145+
if err != nil {
146+
return err
147+
}
148+
}
149+
150+
return nil
151+
}

0 commit comments

Comments
 (0)