github.com/decred/politeia@v1.4.0/politeiawww/cmd/pictl/cmdvoteauthorize.go (about)

     1  // Copyright (c) 2020-2021 The Decred developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package main
     6  
     7  import (
     8  	"encoding/hex"
     9  	"fmt"
    10  	"strconv"
    11  
    12  	"github.com/decred/politeia/politeiad/api/v1/identity"
    13  	rcv1 "github.com/decred/politeia/politeiawww/api/records/v1"
    14  	tkv1 "github.com/decred/politeia/politeiawww/api/ticketvote/v1"
    15  	pclient "github.com/decred/politeia/politeiawww/client"
    16  	"github.com/decred/politeia/politeiawww/cmd/shared"
    17  	"github.com/decred/politeia/util"
    18  )
    19  
    20  // cmdVoteAuthorize authorizes a ticket vote or revokes a previous
    21  // authorization.
    22  type cmdVoteAuthorize struct {
    23  	Args struct {
    24  		Token   string `positional-arg-name:"token" required:"true"`
    25  		Action  string `positional-arg-name:"action"`
    26  		Version uint32 `positional-arg-name:"version"`
    27  	} `positional-args:"true"`
    28  }
    29  
    30  // Execute executes the cmdVoteAuthorize command.
    31  //
    32  // This function satisfies the go-flags Commander interface.
    33  func (c *cmdVoteAuthorize) Execute(args []string) error {
    34  	// Verify action
    35  	var action tkv1.AuthActionT
    36  	switch c.Args.Action {
    37  	case "authorize":
    38  		action = tkv1.AuthActionAuthorize
    39  	case "revoke":
    40  		action = tkv1.AuthActionRevoke
    41  	case "":
    42  		// Default to authorize
    43  		action = tkv1.AuthActionAuthorize
    44  	default:
    45  		return fmt.Errorf("Invalid action; \n%v", voteAuthorizeHelpMsg)
    46  	}
    47  
    48  	// Verify user identity. An identity is required to sign the vote
    49  	// authorization.
    50  	if cfg.Identity == nil {
    51  		return shared.ErrUserIdentityNotFound
    52  	}
    53  
    54  	// Setup client
    55  	opts := pclient.Opts{
    56  		HTTPSCert:  cfg.HTTPSCert,
    57  		Cookies:    cfg.Cookies,
    58  		HeaderCSRF: cfg.CSRF,
    59  		Verbose:    cfg.Verbose,
    60  		RawJSON:    cfg.RawJSON,
    61  	}
    62  	pc, err := pclient.New(cfg.Host, opts)
    63  	if err != nil {
    64  		return err
    65  	}
    66  
    67  	// Get record version
    68  	version := c.Args.Version
    69  	if version == 0 {
    70  		d := rcv1.Details{
    71  			Token: c.Args.Token,
    72  		}
    73  		r, err := pc.RecordDetails(d)
    74  		if err != nil {
    75  			return err
    76  		}
    77  		version = r.Version
    78  	}
    79  
    80  	// Setup request
    81  	msg := c.Args.Token + strconv.FormatUint(uint64(version), 10) +
    82  		string(action)
    83  	sig := cfg.Identity.SignMessage([]byte(msg))
    84  	a := tkv1.Authorize{
    85  		Token:     c.Args.Token,
    86  		Version:   version,
    87  		Action:    action,
    88  		PublicKey: cfg.Identity.Public.String(),
    89  		Signature: hex.EncodeToString(sig[:]),
    90  	}
    91  
    92  	// Send request
    93  	ar, err := pc.TicketVoteAuthorize(a)
    94  	if err != nil {
    95  		return err
    96  	}
    97  
    98  	// Verify receipt
    99  	vr, err := client.Version()
   100  	if err != nil {
   101  		return err
   102  	}
   103  	serverID, err := identity.PublicIdentityFromString(vr.PubKey)
   104  	if err != nil {
   105  		return err
   106  	}
   107  	s, err := util.ConvertSignature(ar.Receipt)
   108  	if err != nil {
   109  		return err
   110  	}
   111  	if !serverID.VerifyMessage([]byte(a.Signature), s) {
   112  		return fmt.Errorf("could not verify receipt")
   113  	}
   114  
   115  	// Print receipt
   116  	printf("Token    : %v\n", a.Token)
   117  	printf("Action   : %v\n", a.Action)
   118  	printf("Timestamp: %v\n", dateAndTimeFromUnix(ar.Timestamp))
   119  	printf("Receipt  : %v\n", ar.Receipt)
   120  
   121  	return nil
   122  }
   123  
   124  // voteAuthorizeHelpMsg is printed to stdout by the help command.
   125  const voteAuthorizeHelpMsg = `voteauthorize "token" "action"
   126  
   127  Authorize or revoke a ticket vote.
   128  
   129  If an action is not provided this command defaults to authorizing a ticket
   130  vote. The user must be the record author.
   131  
   132  Valid actions:
   133    authorize  authorize a vote
   134    revoke     revoke a previous authorization
   135  
   136  Arguments:
   137  1. token    (string, required)  Record token.
   138  2. action   (string, optional)  Authorize vote action.`