code.vegaprotocol.io/vega@v0.79.0/cmd/vegawallet/commands/message_verify.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  
    31  	"github.com/spf13/cobra"
    32  )
    33  
    34  var (
    35  	verifyMessageLong = cli.LongDesc(`
    36  		Verify a message against a signature.
    37  
    38  		The signature has to be generated by Ed25519 cryptographic algorithm.
    39  	`)
    40  
    41  	verifyMessageExample = cli.Examples(`
    42  		# Verify the signature of a message
    43  		{{.Software}} message verify --message MESSAGE --signature SIGNATURE --pubkey PUBKEY
    44  	`)
    45  )
    46  
    47  type VerifyMessageHandler func(api.AdminVerifyMessageParams) (api.AdminVerifyMessageResult, error)
    48  
    49  func NewCmdVerifyMessage(w io.Writer, rf *RootFlags) *cobra.Command {
    50  	h := func(params api.AdminVerifyMessageParams) (api.AdminVerifyMessageResult, error) {
    51  		verifyMessage := api.NewAdminVerifyMessage()
    52  		rawResult, errorDetails := verifyMessage.Handle(context.Background(), params)
    53  		if errorDetails != nil {
    54  			return api.AdminVerifyMessageResult{}, errors.New(errorDetails.Data)
    55  		}
    56  		return rawResult.(api.AdminVerifyMessageResult), nil
    57  	}
    58  	return BuildCmdVerifyMessage(w, h, rf)
    59  }
    60  
    61  func BuildCmdVerifyMessage(w io.Writer, handler VerifyMessageHandler, rf *RootFlags) *cobra.Command {
    62  	f := &VerifyMessageFlags{}
    63  
    64  	cmd := &cobra.Command{
    65  		Use:     "verify",
    66  		Short:   "Verify a message against a signature",
    67  		Long:    verifyMessageLong,
    68  		Example: verifyMessageExample,
    69  		RunE: func(_ *cobra.Command, _ []string) error {
    70  			req, err := f.Validate()
    71  			if err != nil {
    72  				return err
    73  			}
    74  
    75  			resp, err := handler(req)
    76  			if err != nil {
    77  				return err
    78  			}
    79  
    80  			switch rf.Output {
    81  			case flags.InteractiveOutput:
    82  				PrintVerifyMessageResponse(w, resp.IsValid)
    83  			case flags.JSONOutput:
    84  				return printer.FprintJSON(w, struct {
    85  					IsValid bool `json:"isValid"`
    86  				}{
    87  					IsValid: resp.IsValid,
    88  				})
    89  			}
    90  
    91  			return nil
    92  		},
    93  	}
    94  
    95  	cmd.Flags().StringVarP(&f.PubKey,
    96  		"pubkey", "k",
    97  		"",
    98  		"Public key associated to the signature (hex-encoded)",
    99  	)
   100  	cmd.Flags().StringVarP(&f.Message,
   101  		"message", "m",
   102  		"",
   103  		"Message to be verified (base64-encoded)",
   104  	)
   105  	cmd.Flags().StringVarP(&f.Signature,
   106  		"signature", "s",
   107  		"",
   108  		"Signature of the message (base64-encoded)",
   109  	)
   110  
   111  	return cmd
   112  }
   113  
   114  type VerifyMessageFlags struct {
   115  	Signature string
   116  	Message   string
   117  	PubKey    string
   118  }
   119  
   120  func (f *VerifyMessageFlags) Validate() (api.AdminVerifyMessageParams, error) {
   121  	req := api.AdminVerifyMessageParams{}
   122  
   123  	if len(f.PubKey) == 0 {
   124  		return api.AdminVerifyMessageParams{}, flags.MustBeSpecifiedError("pubkey")
   125  	}
   126  	req.PublicKey = f.PubKey
   127  
   128  	if len(f.Signature) == 0 {
   129  		return api.AdminVerifyMessageParams{}, flags.MustBeSpecifiedError("signature")
   130  	}
   131  	_, err := base64.StdEncoding.DecodeString(f.Signature)
   132  	if err != nil {
   133  		return api.AdminVerifyMessageParams{}, flags.MustBase64EncodedError("signature")
   134  	}
   135  	req.EncodedSignature = f.Signature
   136  
   137  	if len(f.Message) == 0 {
   138  		return api.AdminVerifyMessageParams{}, flags.MustBeSpecifiedError("message")
   139  	}
   140  	_, err = base64.StdEncoding.DecodeString(f.Message)
   141  	if err != nil {
   142  		return api.AdminVerifyMessageParams{}, flags.MustBase64EncodedError("message")
   143  	}
   144  	req.EncodedMessage = f.Message
   145  
   146  	return req, nil
   147  }
   148  
   149  func PrintVerifyMessageResponse(w io.Writer, isValid bool) {
   150  	p := printer.NewInteractivePrinter(w)
   151  
   152  	str := p.String()
   153  	defer p.Print(str)
   154  
   155  	if isValid {
   156  		str.CheckMark().SuccessText("Valid signature").NextSection()
   157  	} else {
   158  		str.CrossMark().DangerText("Invalid signature").NextSection()
   159  	}
   160  
   161  	str.BlueArrow().InfoText("Sign a message").NextLine()
   162  	str.Text("To sign a message, see the following command:").NextSection()
   163  	str.Code(fmt.Sprintf("%s sign --help", os.Args[0])).NextLine()
   164  }