github.com/vchain-us/vcn@v0.9.11-0.20210921212052-a2484d23c0b3/pkg/cmd/serve/sign.go (about)

     1  /*
     2   * Copyright (c) 2018-2020 vChain, Inc. All Rights Reserved.
     3   * This software is released under GPL3.
     4   * The full license information can be found under:
     5   * https://www.gnu.org/licenses/gpl-3.0.en.html
     6   *
     7   */
     8  
     9  package serve
    10  
    11  import (
    12  	"encoding/json"
    13  	"fmt"
    14  	"net/http"
    15  	"strings"
    16  
    17  	"github.com/vchain-us/vcn/pkg/api"
    18  	"github.com/vchain-us/vcn/pkg/cmd/internal/types"
    19  	"github.com/vchain-us/vcn/pkg/extractor"
    20  	"github.com/vchain-us/vcn/pkg/meta"
    21  )
    22  
    23  type handler struct {
    24  	lcHost          string
    25  	lcPort          string
    26  	lcCert          string
    27  	lcSkipTlsVerify bool
    28  	lcNoTls         bool
    29  }
    30  
    31  func (sh *handler) signHandler(state meta.Status) func(w http.ResponseWriter, r *http.Request) {
    32  	return func(w http.ResponseWriter, r *http.Request) {
    33  		s := state
    34  		k := make(map[string]bool)
    35  		for _, scheme := range extractor.Schemes() {
    36  			k[scheme] = true
    37  		}
    38  		if sh.lcHost != "" && sh.lcPort != "" {
    39  			// todo @Michele move getLcUser in handler sh constructor
    40  			lcUser, err := getLcUser(r, sh.lcHost, sh.lcPort, sh.lcCert, sh.lcSkipTlsVerify, sh.lcNoTls)
    41  			if err != nil {
    42  				writeError(w, http.StatusBadGateway, err)
    43  				return
    44  			}
    45  			lcSign(lcUser, s, k, w, r)
    46  			return
    47  		}
    48  		sign(s, k, w, r)
    49  	}
    50  }
    51  
    52  func sign(status meta.Status, kinds map[string]bool, w http.ResponseWriter, r *http.Request) {
    53  	user, passphrase, err := getCredential(r)
    54  	if err != nil {
    55  		writeError(w, http.StatusUnauthorized, err)
    56  		return
    57  	}
    58  	if user == nil {
    59  		writeError(w, http.StatusUnauthorized, fmt.Errorf("bad or missing credentials"))
    60  		return
    61  	}
    62  
    63  	keyin, _, offline, err := user.Secret()
    64  	if err != nil {
    65  		writeError(w, http.StatusConflict, err)
    66  		return
    67  	}
    68  	if offline {
    69  		writeError(w, http.StatusConflict, fmt.Errorf("offline secret is not yet supported"))
    70  		return
    71  	}
    72  
    73  	opts := []api.SignOption{
    74  		api.SignWithKey(keyin, passphrase),
    75  		api.SignWithStatus(status),
    76  	}
    77  
    78  	if _, public := r.URL.Query()["public"]; public {
    79  		opts = append(opts, api.SignWithVisibility(meta.VisibilityPublic))
    80  	}
    81  
    82  	decoder := json.NewDecoder(r.Body)
    83  	var artifact api.Artifact
    84  	err = decoder.Decode(&artifact)
    85  
    86  	if err != nil {
    87  		writeError(w, http.StatusBadRequest, err)
    88  		return
    89  	}
    90  
    91  	if artifact.Name == "" {
    92  		writeError(w, http.StatusBadRequest, fmt.Errorf("name cannot be empty"))
    93  		return
    94  	}
    95  
    96  	if !kinds[artifact.Kind] {
    97  		writeError(w, http.StatusBadRequest, fmt.Errorf(`"%s" is not a valid value for kind`, artifact.Kind))
    98  		return
    99  	}
   100  
   101  	artifact.Hash = strings.ToLower(artifact.Hash)
   102  
   103  	verification, err := user.Sign(
   104  		artifact,
   105  		opts...,
   106  	)
   107  
   108  	// todo(ameingast/leogr): remove reduntat event - need backend improvement
   109  	api.TrackPublisher(user, meta.VcnSignEvent)
   110  	api.TrackSign(user, artifact.Hash, artifact.Name, status)
   111  
   112  	if err != nil {
   113  		writeError(w, http.StatusBadRequest, err)
   114  		return
   115  	}
   116  
   117  	var ar *api.ArtifactResponse
   118  	if !verification.Unknown() {
   119  		ar, _ = api.LoadArtifact(user, artifact.Hash, verification.MetaHash())
   120  	}
   121  
   122  	writeResult(w, http.StatusOK, types.NewResult(&artifact, ar, verification))
   123  }