...

Source file src/github.com/sassoftware/relic/signers/transform.go

Documentation: github.com/sassoftware/relic/signers

     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 signers
    18  
    19  // Some package types can't be signed as a stream as-is, so we transform them
    20  // into something else (a tarball) and upload that to the server. The server
    21  // signs the tar, returns the signature blob, and the client inserts the blob
    22  // into the original file. This mechanism can also be used for cases that don't
    23  // need a transform on the upload but do need special processing on the result
    24  // side. A default implementation that handles patching, copying, and
    25  // overwriting is provided.
    26  
    27  import (
    28  	"fmt"
    29  	"io"
    30  	"io/ioutil"
    31  	"os"
    32  
    33  	"github.com/sassoftware/relic/lib/atomicfile"
    34  	"github.com/sassoftware/relic/lib/binpatch"
    35  )
    36  
    37  type Transformer interface {
    38  	// Return a stream that will be uploaded to a remote server. This may be
    39  	// called multiple times in case of failover.
    40  	GetReader() (stream io.Reader, err error)
    41  	// Apply a HTTP response to the named destination file
    42  	Apply(dest, mimetype string, result io.Reader) error
    43  }
    44  
    45  // Return the transform for the given module if it has one, otherwise return
    46  // the default transform.
    47  func (s *Signer) GetTransform(f *os.File, opts SignOpts) (Transformer, error) {
    48  	if s != nil && s.Transform != nil {
    49  		return s.Transform(f, opts)
    50  	}
    51  	return fileProducer{f}, nil
    52  }
    53  
    54  func DefaultTransform(f *os.File) Transformer {
    55  	return fileProducer{f}
    56  }
    57  
    58  // Dummy implementation that sends the original file as a request, and
    59  // either applies a binary patch or overwrites the whole file depending on the
    60  // MIME type.
    61  
    62  type fileProducer struct {
    63  	f *os.File
    64  }
    65  
    66  func (p fileProducer) GetReader() (io.Reader, error) {
    67  	if _, err := p.f.Seek(0, io.SeekStart); err != nil {
    68  		return nil, fmt.Errorf("failed to seek input file: %s", err)
    69  	}
    70  	return p.f, nil
    71  }
    72  
    73  // If the response is a binpatch, apply it. Otherwise overwrite the destination
    74  // file with the response
    75  func (p fileProducer) Apply(dest, mimetype string, result io.Reader) error {
    76  	if mimetype == binpatch.MimeType {
    77  		return ApplyBinPatch(p.f, dest, result)
    78  	}
    79  	f, err := atomicfile.WriteAny(dest)
    80  	if err != nil {
    81  		return err
    82  	}
    83  	if _, err := io.Copy(f, result); err != nil {
    84  		return err
    85  	}
    86  	p.f.Close()
    87  	return f.Commit()
    88  }
    89  
    90  func ApplyBinPatch(src *os.File, dest string, result io.Reader) error {
    91  	blob, err := ioutil.ReadAll(result)
    92  	if err != nil {
    93  		return err
    94  	}
    95  	patch, err := binpatch.Load(blob)
    96  	if err != nil {
    97  		return err
    98  	}
    99  	return patch.Apply(src, dest)
   100  }
   101  

View as plain text