1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package token
18
19 import (
20 "bytes"
21 "context"
22 "errors"
23 "fmt"
24 "os"
25
26 "github.com/sassoftware/relic/cmdline/shared"
27 "github.com/sassoftware/relic/internal/signinit"
28 "github.com/sassoftware/relic/signers"
29 "github.com/spf13/cobra"
30 )
31
32 var SignCmd = &cobra.Command{
33 Use: "sign",
34 Short: "Sign a package using a token",
35 RunE: signCmd,
36 }
37
38 var (
39 argIfUnsigned bool
40 argSigType string
41 argOutput string
42 )
43
44 func init() {
45 shared.RootCmd.AddCommand(SignCmd)
46 addKeyFlags(SignCmd)
47 SignCmd.Flags().StringVarP(&argFile, "file", "f", "", "Input file to sign")
48 SignCmd.Flags().StringVarP(&argOutput, "output", "o", "", "Output file")
49 SignCmd.Flags().StringVarP(&argSigType, "sig-type", "T", "", "Specify signature type (default: auto-detect)")
50 SignCmd.Flags().BoolVar(&argIfUnsigned, "if-unsigned", false, "Skip signing if the file already has a signature")
51 shared.AddDigestFlag(SignCmd)
52 shared.AddLateHook(func() {
53 signers.MergeFlags(SignCmd.Flags())
54 })
55 }
56
57 func signCmd(cmd *cobra.Command, args []string) error {
58 if argFile == "" || argKeyName == "" {
59 return errors.New("--file and --key are required")
60 }
61 if argOutput == "" {
62 argOutput = argFile
63 }
64 mod, err := signers.ByFile(argFile, argSigType)
65 if err != nil {
66 return shared.Fail(err)
67 }
68 if mod.Sign == nil {
69 return shared.Fail(errors.New("can't sign this type of file"))
70 }
71 flags, err := mod.FlagsFromCmdline(cmd.Flags())
72 if err != nil {
73 return shared.Fail(err)
74 }
75 hash, err := shared.GetDigest()
76 if err != nil {
77 return shared.Fail(err)
78 }
79 token, err := openTokenByKey(argKeyName)
80 if err != nil {
81 return shared.Fail(err)
82 }
83 cert, opts, err := signinit.Init(context.Background(), mod, token, argKeyName, hash, flags)
84 if err != nil {
85 return shared.Fail(err)
86 }
87 opts.Path = argFile
88 infile, err := os.OpenFile(argFile, os.O_RDWR, 0)
89 if err != nil {
90 return shared.Fail(err)
91 }
92 defer infile.Close()
93 if argIfUnsigned {
94 if signed, err := mod.IsSigned(infile); err != nil {
95 return shared.Fail(err)
96 } else if signed {
97 fmt.Fprintf(os.Stderr, "skipping already-signed file: %s\n", argFile)
98 return nil
99 }
100 if _, err := infile.Seek(0, 0); err != nil {
101 return shared.Fail(fmt.Errorf("failed to rewind input file: %s", err))
102 }
103 }
104
105 transform, err := mod.GetTransform(infile, *opts)
106 if err != nil {
107 return shared.Fail(err)
108 }
109 stream, err := transform.GetReader()
110 if err != nil {
111 return shared.Fail(err)
112 }
113 blob, err := mod.Sign(stream, cert, *opts)
114 if err != nil {
115 return shared.Fail(err)
116 }
117 mimeType := opts.Audit.GetMimeType()
118 if err := transform.Apply(argOutput, mimeType, bytes.NewReader(blob)); err != nil {
119 return shared.Fail(err)
120 }
121
122 if mod.Fixup != nil {
123 f, err := os.OpenFile(argOutput, os.O_RDWR, 0)
124 if err != nil {
125 return shared.Fail(err)
126 }
127 defer f.Close()
128 if err := mod.Fixup(f); err != nil {
129 return shared.Fail(err)
130 }
131 }
132 if err := signinit.PublishAudit(opts.Audit); err != nil {
133 return err
134 }
135 fmt.Fprintln(os.Stderr, "Signed", argFile)
136 return nil
137 }
138
View as plain text