feat(autocli): add address validation (#15449)
## Description Closes: #13287 --- ### Author Checklist *All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.* I have... - [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] added `!` to the type prefix if API or client breaking change - [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/main/CONTRIBUTING.md#pr-targeting)) - [ ] provided a link to the relevant issue or specification - [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/main/docs/docs/building-modules) - [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/main/CONTRIBUTING.md#testing) - [ ] added a changelog entry to `CHANGELOG.md` - [ ] included comments for [documenting Go code](https://blog.golang.org/godoc) - [ ] updated the relevant documentation or specification - [ ] reviewed "Files changed" and left comments if necessary - [ ] confirmed all CI checks have passed ### Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* I have... - [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] confirmed `!` in the type prefix if API or client breaking change - [ ] confirmed all author checklist items have been addressed - [ ] reviewed state machine logic - [ ] reviewed API design and naming - [ ] reviewed documentation is accurate - [ ] reviewed tests and test coverage - [ ] manually tested (if applicable)
This commit is contained in:
parent
c77bcc22c3
commit
4866d9aa2e
@ -1,8 +1,10 @@
|
||||
package autocli
|
||||
|
||||
import (
|
||||
autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/spf13/cobra"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
@ -41,6 +43,7 @@ func (b *Builder) buildMethodCommandCommon(descriptor protoreflect.MethodDescrip
|
||||
Version: options.Version,
|
||||
}
|
||||
|
||||
cmd.SetContext(context.Background())
|
||||
binder, err := b.AddMessageFlags(cmd.Context(), cmd.Flags(), inputType, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -108,11 +111,9 @@ func (b *Builder) enhanceCommandCommon(cmd *cobra.Command, moduleOptions map[str
|
||||
func (b *Builder) outOrStdoutFormat(cmd *cobra.Command, out []byte) error {
|
||||
var err error
|
||||
outputType := cmd.Flag(flags.FlagOutput)
|
||||
if outputType == nil {
|
||||
return fmt.Errorf("output flag not found")
|
||||
|
||||
}
|
||||
if outputType.Value.String() == "text" {
|
||||
// if the output type is text, convert the json to yaml
|
||||
// if output type is json or nil, default to json
|
||||
if outputType != nil && outputType.Value.String() == "text" {
|
||||
out, err = yaml.JSONToYAML(out)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@ -2,6 +2,9 @@ package autocli
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
reflectionv2alpha1 "cosmossdk.io/api/cosmos/base/reflection/v2alpha1"
|
||||
"cosmossdk.io/client/v2/autocli/flag"
|
||||
"cosmossdk.io/client/v2/internal/testpb"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/spf13/cobra"
|
||||
@ -16,6 +19,7 @@ import (
|
||||
func testExecCommon(t *testing.T, buildModuleCommand func(string, *Builder) (*cobra.Command, error), args ...string) *testClientConn {
|
||||
server := grpc.NewServer()
|
||||
testpb.RegisterQueryServer(server, &testEchoServer{})
|
||||
reflectionv2alpha1.RegisterReflectionServiceServer(server, &testReflectionServer{})
|
||||
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
assert.NilError(t, err)
|
||||
go func() {
|
||||
@ -41,6 +45,11 @@ func testExecCommon(t *testing.T, buildModuleCommand func(string, *Builder) (*co
|
||||
errorOut: &bytes.Buffer{},
|
||||
}
|
||||
b := &Builder{
|
||||
Builder: flag.Builder{
|
||||
|
||||
GetClientConn: func() (grpc.ClientConnInterface, error) {
|
||||
return conn, nil
|
||||
}},
|
||||
GetClientConn: func(*cobra.Command) (grpc.ClientConnInterface, error) {
|
||||
return conn, nil
|
||||
},
|
||||
@ -57,3 +66,17 @@ func testExecCommon(t *testing.T, buildModuleCommand func(string, *Builder) (*co
|
||||
cmd.Execute()
|
||||
return conn
|
||||
}
|
||||
|
||||
type testReflectionServer struct {
|
||||
reflectionv2alpha1.UnimplementedReflectionServiceServer
|
||||
}
|
||||
|
||||
func (t testReflectionServer) GetConfigurationDescriptor(_ context.Context, client *reflectionv2alpha1.GetConfigurationDescriptorRequest) (*reflectionv2alpha1.GetConfigurationDescriptorResponse, error) {
|
||||
return &reflectionv2alpha1.GetConfigurationDescriptorResponse{
|
||||
Config: &reflectionv2alpha1.ConfigurationDescriptor{
|
||||
Bech32AccountAddressPrefix: "cosmos",
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
var _ reflectionv2alpha1.ReflectionServiceServer = testReflectionServer{}
|
||||
|
||||
@ -2,14 +2,31 @@ package flag
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
reflectionv2alpha1 "cosmossdk.io/api/cosmos/base/reflection/v2alpha1"
|
||||
"github.com/cosmos/cosmos-sdk/types"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
)
|
||||
|
||||
type addressStringType struct{}
|
||||
|
||||
func (a addressStringType) NewValue(_ context.Context, _ *Builder) Value {
|
||||
return &addressValue{}
|
||||
func (a addressStringType) NewValue(ctx context.Context, b *Builder) Value {
|
||||
|
||||
if b.AddressPrefix == "" {
|
||||
conn, err := b.GetClientConn()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
reflectionClient := reflectionv2alpha1.NewReflectionServiceClient(conn)
|
||||
resp, err := reflectionClient.GetConfigurationDescriptor(ctx, &reflectionv2alpha1.GetConfigurationDescriptorRequest{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if resp == nil || resp.Config == nil {
|
||||
panic("bech32 account address prefix is not set")
|
||||
}
|
||||
b.AddressPrefix = resp.Config.Bech32AccountAddressPrefix
|
||||
}
|
||||
return &addressValue{addressPrefix: b.AddressPrefix}
|
||||
}
|
||||
|
||||
func (a addressStringType) DefaultValue() string {
|
||||
@ -17,7 +34,8 @@ func (a addressStringType) DefaultValue() string {
|
||||
}
|
||||
|
||||
type addressValue struct {
|
||||
value string
|
||||
value string
|
||||
addressPrefix string
|
||||
}
|
||||
|
||||
func (a addressValue) Get(protoreflect.Value) (protoreflect.Value, error) {
|
||||
@ -28,9 +46,14 @@ func (a addressValue) String() string {
|
||||
return a.value
|
||||
}
|
||||
|
||||
// Set implements the flag.Value interface for addressValue it only supports bech32 addresses.
|
||||
func (a *addressValue) Set(s string) error {
|
||||
_, err := types.GetFromBech32(s, a.addressPrefix)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.value = s
|
||||
// TODO handle bech32 validation
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package flag
|
||||
|
||||
import (
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/protobuf/reflect/protodesc"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
"google.golang.org/protobuf/reflect/protoregistry"
|
||||
@ -21,6 +22,11 @@ type Builder struct {
|
||||
|
||||
messageFlagTypes map[protoreflect.FullName]Type
|
||||
scalarFlagTypes map[string]Type
|
||||
|
||||
// AddressPrefix is the prefix for the address flag
|
||||
AddressPrefix string
|
||||
// reflectionClient is the reflection client for the address flag
|
||||
GetClientConn func() (grpc.ClientConnInterface, error)
|
||||
}
|
||||
|
||||
func (b *Builder) init() {
|
||||
@ -34,6 +40,7 @@ func (b *Builder) init() {
|
||||
b.scalarFlagTypes = map[string]Type{}
|
||||
b.scalarFlagTypes["cosmos.AddressString"] = addressStringType{}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (b *Builder) DefineMessageFlagType(messageName protoreflect.FullName, flagType Type) {
|
||||
|
||||
@ -179,7 +179,7 @@ func TestEverythingMsg(t *testing.T) {
|
||||
"--str", "def",
|
||||
"--timestamp", "2019-01-02T00:01:02Z",
|
||||
"--a-coin", `{"denom":"foo","amount":"100000"}`,
|
||||
"--an-address", "cosmossdghdsfoi2134sdgh",
|
||||
"--an-address", "cosmos1y74p8wyy4enfhfn342njve6cjmj5c8dtl6emdk",
|
||||
"--bz", "c2RncXdlZndkZ3NkZw==",
|
||||
"--page-count-total",
|
||||
"--page-key", "MTIzNTQ4N3NnaGRhcw==",
|
||||
|
||||
@ -117,7 +117,7 @@ func TestEverything(t *testing.T) {
|
||||
"--str", "def",
|
||||
"--timestamp", "2019-01-02T00:01:02Z",
|
||||
"--a-coin", `{"denom":"foo","amount":"100000"}`,
|
||||
"--an-address", "cosmossdghdsfoi2134sdgh",
|
||||
"--an-address", "cosmos1y74p8wyy4enfhfn342njve6cjmj5c8dtl6emdk",
|
||||
"--bz", "c2RncXdlZndkZ3NkZw==",
|
||||
"--page-count-total",
|
||||
"--page-key", "MTIzNTQ4N3NnaGRhcw==",
|
||||
@ -157,6 +157,29 @@ func TestOptions(t *testing.T) {
|
||||
assert.Equal(t, uint64(5), lastReq.U64) // no opt default value got set
|
||||
}
|
||||
|
||||
func TestAddressValidation(t *testing.T) {
|
||||
conn := testExecCommon(t, buildModuleQueryCommand,
|
||||
"echo",
|
||||
"1", "abc", `{"denom":"foo","amount":"1"}`,
|
||||
"--an-address", "cosmos1y74p8wyy4enfhfn342njve6cjmj5c8dtl6emdk",
|
||||
)
|
||||
assert.Equal(t, "", conn.errorOut.String())
|
||||
|
||||
conn = testExecCommon(t, buildModuleQueryCommand,
|
||||
"echo",
|
||||
"1", "abc", `{"denom":"foo","amount":"1"}`,
|
||||
"--an-address", "regen1y74p8wyy4enfhfn342njve6cjmj5c8dtl6emdk",
|
||||
)
|
||||
assert.Assert(t, strings.Contains(conn.errorOut.String(), "Error: invalid argument"))
|
||||
|
||||
conn = testExecCommon(t, buildModuleQueryCommand,
|
||||
"echo",
|
||||
"1", "abc", `{"denom":"foo","amount":"1"}`,
|
||||
"--an-address", "cosmps1BAD_ENCODING",
|
||||
)
|
||||
assert.Assert(t, strings.Contains(conn.errorOut.String(), "Error: invalid argument"))
|
||||
}
|
||||
|
||||
func TestOutputFormat(t *testing.T) {
|
||||
conn := testExecCommon(t, buildModuleQueryCommand,
|
||||
"echo",
|
||||
|
||||
@ -4,7 +4,7 @@ go 1.20
|
||||
|
||||
require (
|
||||
cosmossdk.io/api v0.3.2-0.20230313131911-55bf5d4efbe7
|
||||
cosmossdk.io/client/v2 v2.0.0-20230314205129-d50cb1ef349f
|
||||
cosmossdk.io/client/v2 v2.0.0-20230320224637-dca0e7374a1d
|
||||
cosmossdk.io/errors v1.0.0-beta.7
|
||||
github.com/cockroachdb/errors v1.9.1
|
||||
github.com/hashicorp/go-multierror v1.1.1
|
||||
|
||||
@ -37,8 +37,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
|
||||
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
|
||||
cosmossdk.io/api v0.3.2-0.20230313131911-55bf5d4efbe7 h1:4LrWK+uGP5IxznxtHHsHD+ZBs2+oZRH2loYOGjHLzZM=
|
||||
cosmossdk.io/api v0.3.2-0.20230313131911-55bf5d4efbe7/go.mod h1:yVns7mKgcsG+hZW/3C5FdJtC6QYWdFIcRlKb9+5HV5g=
|
||||
cosmossdk.io/client/v2 v2.0.0-20230314205129-d50cb1ef349f h1:1RHTrQqqtfKuMoZayZhlVR4cSAUAFXV7aHUolVom6pc=
|
||||
cosmossdk.io/client/v2 v2.0.0-20230314205129-d50cb1ef349f/go.mod h1:PHHjwtEPxeSQmCZlDCb12ZZf53Mz6T5z2bAEYtlM7D4=
|
||||
cosmossdk.io/client/v2 v2.0.0-20230320224637-dca0e7374a1d h1:9mBIeO0ZhCalqS3pJiZ1fs+Nn93E7rU4+Hv7QVINbNM=
|
||||
cosmossdk.io/client/v2 v2.0.0-20230320224637-dca0e7374a1d/go.mod h1:qX4UABq4VI1ccJn4H4MIJx5/HvjRiaVaImovbnPXNXc=
|
||||
cosmossdk.io/collections v0.0.0-20230309163709-87da587416ba h1:S4PYij/tX3Op/hwenVEN9D+M27JRcwSwVqE3UA0BnwM=
|
||||
cosmossdk.io/collections v0.0.0-20230309163709-87da587416ba/go.mod h1:lpS+G8bGC2anqzWdndTzjnQnuMO/qAcgZUkGJp4i3rc=
|
||||
cosmossdk.io/core v0.6.1 h1:OBy7TI2W+/gyn2z40vVvruK3di+cAluinA6cybFbE7s=
|
||||
|
||||
@ -93,13 +93,14 @@ func RemoteCommand(config *Config, configDir string) ([]*cobra.Command, error) {
|
||||
Builder: flag.Builder{
|
||||
TypeResolver: &dynamicTypeResolver{chainInfo},
|
||||
FileResolver: chainInfo.ProtoFiles,
|
||||
},
|
||||
GetClientConn: func() (grpc.ClientConnInterface, error) {
|
||||
return chainInfo.OpenClient()
|
||||
}},
|
||||
GetClientConn: func(command *cobra.Command) (grpc.ClientConnInterface, error) {
|
||||
return chainInfo.OpenClient()
|
||||
},
|
||||
AddQueryConnFlags: func(command *cobra.Command) {},
|
||||
}
|
||||
|
||||
var (
|
||||
update bool
|
||||
reconfig bool
|
||||
|
||||
Loading…
Reference in New Issue
Block a user