Skip to content

Commit

Permalink
feat(autocli): add address validation (#15449)
Browse files Browse the repository at this point in the history
## 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)
  • Loading branch information
JeancarloBarrios authored Mar 22, 2023
1 parent c77bcc2 commit 4866d9a
Show file tree
Hide file tree
Showing 9 changed files with 96 additions and 18 deletions.
13 changes: 7 additions & 6 deletions client/v2/autocli/common.go
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
23 changes: 23 additions & 0 deletions client/v2/autocli/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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() {
Expand All @@ -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
},
Expand All @@ -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{}
33 changes: 28 additions & 5 deletions client/v2/autocli/flag/address.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,40 @@ 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 {
return ""
}

type addressValue struct {
value string
value string
addressPrefix string
}

func (a addressValue) Get(protoreflect.Value) (protoreflect.Value, error) {
Expand All @@ -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
}

Expand Down
7 changes: 7 additions & 0 deletions client/v2/autocli/flag/builder.go
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -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() {
Expand All @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion client/v2/autocli/msg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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==",
Expand Down
25 changes: 24 additions & 1 deletion client/v2/autocli/query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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==",
Expand Down Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion tools/hubl/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions tools/hubl/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down
5 changes: 3 additions & 2 deletions tools/hubl/internal/remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 4866d9a

Please sign in to comment.