...

Source file src/github.com/sassoftware/relic/cmdline/remotecmd/signcmd.go

Documentation: github.com/sassoftware/relic/cmdline/remotecmd

     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 remotecmd
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"net/url"
    23  	"os"
    24  	"path/filepath"
    25  
    26  	"github.com/sassoftware/relic/cmdline/shared"
    27  	"github.com/sassoftware/relic/signers"
    28  	"github.com/spf13/cobra"
    29  )
    30  
    31  var SignCmd = &cobra.Command{
    32  	Use:   "sign",
    33  	Short: "Sign a package using a remote signing server",
    34  	RunE:  signCmd,
    35  }
    36  
    37  var (
    38  	argIfUnsigned bool
    39  	argSigType    string
    40  )
    41  
    42  func init() {
    43  	RemoteCmd.AddCommand(SignCmd)
    44  	SignCmd.Flags().StringVarP(&argKeyName, "key", "k", "", "Name of key on remote server to use")
    45  	SignCmd.Flags().StringVarP(&argFile, "file", "f", "", "Input file to sign")
    46  	SignCmd.Flags().StringVarP(&argOutput, "output", "o", "", "Output file. Defaults to same as --file.")
    47  	SignCmd.Flags().StringVarP(&argSigType, "sig-type", "T", "", "Specify signature type (default: auto-detect)")
    48  	SignCmd.Flags().BoolVar(&argIfUnsigned, "if-unsigned", false, "Skip signing if the file already has a signature")
    49  	shared.AddDigestFlag(SignCmd)
    50  	shared.AddLateHook(func() {
    51  		signers.MergeFlags(SignCmd.Flags())
    52  	})
    53  }
    54  
    55  func signCmd(cmd *cobra.Command, args []string) (err error) {
    56  	if argFile == "" || argKeyName == "" {
    57  		return errors.New("--file and --key are required")
    58  	}
    59  	if argOutput == "" {
    60  		argOutput = argFile
    61  	}
    62  	// detect signature type
    63  	mod, err := signers.ByFile(argFile, argSigType)
    64  	if err != nil {
    65  		return shared.Fail(err)
    66  	}
    67  	if mod.Sign == nil {
    68  		return shared.Fail(errors.New("can't sign this type of file"))
    69  	}
    70  	// parse signer-specific flags
    71  	flags, err := mod.FlagsFromCmdline(cmd.Flags())
    72  	if err != nil {
    73  		return shared.Fail(err)
    74  	}
    75  	var infile *os.File
    76  	if argFile == "-" {
    77  		if argIfUnsigned {
    78  			return shared.Fail(errors.New("cannot use --if-unsigned with standard input"))
    79  		}
    80  		if !mod.AllowStdin {
    81  			return shared.Fail(errors.New("this signature type does not support reading from stdin"))
    82  		}
    83  		infile = os.Stdin
    84  	} else {
    85  		// open for writing so in-place patch works
    86  		if argOutput == argFile {
    87  			infile, err = os.OpenFile(argFile, os.O_RDWR, 0)
    88  		} else {
    89  			infile, err = os.Open(argFile)
    90  		}
    91  		if err != nil {
    92  			return shared.Fail(err)
    93  		}
    94  		defer infile.Close()
    95  	}
    96  	if argIfUnsigned {
    97  		if signed, err := mod.IsSigned(infile); err != nil {
    98  			return shared.Fail(err)
    99  		} else if signed {
   100  			fmt.Fprintf(os.Stderr, "skipping already-signed file: %s\n", argFile)
   101  			return nil
   102  		}
   103  		if _, err := infile.Seek(0, 0); err != nil {
   104  			return shared.Fail(fmt.Errorf("failed to rewind input file: %s", err))
   105  		}
   106  	}
   107  	// transform input if needed
   108  	hash, err := shared.GetDigest()
   109  	if err != nil {
   110  		return err
   111  	}
   112  	opts := signers.SignOpts{
   113  		Path:  argFile,
   114  		Hash:  hash,
   115  		Flags: flags,
   116  	}
   117  	transform, err := mod.GetTransform(infile, opts)
   118  	if err != nil {
   119  		return shared.Fail(err)
   120  	}
   121  	// build request
   122  	values := url.Values{}
   123  	values.Add("key", argKeyName)
   124  	values.Add("filename", filepath.Base(argFile))
   125  	values.Add("sigtype", mod.Name)
   126  	if err := flags.ToQuery(values); err != nil {
   127  		return shared.Fail(err)
   128  	}
   129  	if err := setDigestQueryParam(values); err != nil {
   130  		return err
   131  	}
   132  	// do request
   133  	response, err := CallRemote("sign", "POST", &values, transform)
   134  	if err != nil {
   135  		return shared.Fail(err)
   136  	}
   137  	defer response.Body.Close()
   138  	// apply the result
   139  	if err := transform.Apply(argOutput, response.Header.Get("Content-Type"), response.Body); err != nil {
   140  		return shared.Fail(err)
   141  	}
   142  	// if needed, do a final fixup step
   143  	if mod.Fixup != nil {
   144  		f, err := os.OpenFile(argOutput, os.O_RDWR, 0)
   145  		if err != nil {
   146  			return shared.Fail(err)
   147  		}
   148  		defer f.Close()
   149  		if err := mod.Fixup(f); err != nil {
   150  			return shared.Fail(err)
   151  		}
   152  	}
   153  
   154  	fmt.Fprintf(os.Stderr, "Signed %s\n", argFile)
   155  	return nil
   156  }
   157  

View as plain text