code.vegaprotocol.io/vega@v0.79.0/cmd/vegawallet/commands/message_sign.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package cmd 17 18 import ( 19 "context" 20 "encoding/base64" 21 "errors" 22 "fmt" 23 "io" 24 "os" 25 26 "code.vegaprotocol.io/vega/cmd/vegawallet/commands/cli" 27 "code.vegaprotocol.io/vega/cmd/vegawallet/commands/flags" 28 "code.vegaprotocol.io/vega/cmd/vegawallet/commands/printer" 29 "code.vegaprotocol.io/vega/wallet/api" 30 "code.vegaprotocol.io/vega/wallet/wallets" 31 32 "github.com/spf13/cobra" 33 ) 34 35 var ( 36 signMessageLong = cli.LongDesc(` 37 Sign any message using a Vega wallet key. 38 `) 39 40 signMessageExample = cli.Examples(` 41 # Sign a message 42 {{.Software}} message sign --message MESSAGE --wallet WALLET --pubkey PUBKEY 43 `) 44 ) 45 46 type SignMessageHandler func(api.AdminSignMessageParams, string) (api.AdminSignMessageResult, error) 47 48 func NewCmdSignMessage(w io.Writer, rf *RootFlags) *cobra.Command { 49 h := func(params api.AdminSignMessageParams, passphrase string) (api.AdminSignMessageResult, error) { 50 ctx := context.Background() 51 52 walletStore, err := wallets.InitialiseStore(rf.Home, false) 53 if err != nil { 54 return api.AdminSignMessageResult{}, fmt.Errorf("couldn't initialise wallets store: %w", err) 55 } 56 defer walletStore.Close() 57 58 if _, errDetails := api.NewAdminUnlockWallet(walletStore).Handle(ctx, api.AdminUnlockWalletParams{ 59 Wallet: params.Wallet, 60 Passphrase: passphrase, 61 }); errDetails != nil { 62 return api.AdminSignMessageResult{}, errors.New(errDetails.Data) 63 } 64 65 rawResult, errorDetails := api.NewAdminSignMessage(walletStore).Handle(ctx, params) 66 if errorDetails != nil { 67 return api.AdminSignMessageResult{}, errors.New(errorDetails.Data) 68 } 69 return rawResult.(api.AdminSignMessageResult), nil 70 } 71 return BuildCmdSignMessage(w, h, rf) 72 } 73 74 func BuildCmdSignMessage(w io.Writer, handler SignMessageHandler, rf *RootFlags) *cobra.Command { 75 f := &SignMessageFlags{} 76 77 cmd := &cobra.Command{ 78 Use: "sign", 79 Short: "Sign a message using a Vega wallet key", 80 Long: signMessageLong, 81 Example: signMessageExample, 82 RunE: func(_ *cobra.Command, _ []string) error { 83 req, pass, err := f.Validate() 84 if err != nil { 85 return err 86 } 87 88 resp, err := handler(req, pass) 89 if err != nil { 90 return err 91 } 92 93 switch rf.Output { 94 case flags.InteractiveOutput: 95 PrintSignMessageResponse(w, resp) 96 case flags.JSONOutput: 97 return printer.FprintJSON(w, struct { 98 Signature string `json:"signature"` 99 }{ 100 Signature: resp.EncodedSignature, 101 }) 102 } 103 104 return nil 105 }, 106 } 107 108 cmd.Flags().StringVarP(&f.Wallet, 109 "wallet", "w", 110 "", 111 "Wallet holding the public key", 112 ) 113 cmd.Flags().StringVarP(&f.PubKey, 114 "pubkey", "k", 115 "", 116 "Public key to use to the sign the message (hex-encoded)", 117 ) 118 cmd.Flags().StringVarP(&f.Message, 119 "message", "m", 120 "", 121 "Message to be verified (base64-encoded)", 122 ) 123 cmd.Flags().StringVarP(&f.PassphraseFile, 124 "passphrase-file", "p", 125 "", 126 "Path to the file containing the wallet's passphrase", 127 ) 128 129 autoCompleteWallet(cmd, rf.Home, "wallet") 130 131 return cmd 132 } 133 134 type SignMessageFlags struct { 135 Wallet string 136 PubKey string 137 Message string 138 PassphraseFile string 139 } 140 141 func (f *SignMessageFlags) Validate() (api.AdminSignMessageParams, string, error) { 142 req := api.AdminSignMessageParams{} 143 144 if len(f.Wallet) == 0 { 145 return api.AdminSignMessageParams{}, "", flags.MustBeSpecifiedError("wallet") 146 } 147 req.Wallet = f.Wallet 148 149 if len(f.PubKey) == 0 { 150 return api.AdminSignMessageParams{}, "", flags.MustBeSpecifiedError("pubkey") 151 } 152 req.PublicKey = f.PubKey 153 154 if len(f.Message) == 0 { 155 return api.AdminSignMessageParams{}, "", flags.MustBeSpecifiedError("message") 156 } 157 _, err := base64.StdEncoding.DecodeString(f.Message) 158 if err != nil { 159 return api.AdminSignMessageParams{}, "", flags.MustBase64EncodedError("message") 160 } 161 req.EncodedMessage = f.Message 162 163 passphrase, err := flags.GetPassphrase(f.PassphraseFile) 164 if err != nil { 165 return api.AdminSignMessageParams{}, "", err 166 } 167 168 return req, passphrase, nil 169 } 170 171 func PrintSignMessageResponse(w io.Writer, req api.AdminSignMessageResult) { 172 p := printer.NewInteractivePrinter(w) 173 174 str := p.String() 175 defer p.Print(str) 176 177 str.CheckMark().SuccessText("Message signature successful").NextSection() 178 str.Text("Signature (base64-encoded):").NextLine().WarningText(req.EncodedSignature).NextSection() 179 180 str.BlueArrow().InfoText("Sign a message").NextLine() 181 str.Text("To verify a message, see the following command:").NextSection() 182 str.Code(fmt.Sprintf("%s verify --help", os.Args[0])).NextLine() 183 }