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.`