From e7ceada9528a070b2af70c1aad6ab62fca5fa91c Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Sun, 24 May 2020 14:29:48 -0400 Subject: [PATCH] REST Client Cleanup & Validation (#523) * cleanup & from validation * Add ValidateBasic calls * Update x/incentive tx requests * Address comments --- x/cdp/client/rest/query.go | 33 ++++++-------- x/cdp/client/rest/tx.go | 78 +++++++++++++++++++++++++++----- x/incentive/client/rest/query.go | 6 ++- x/incentive/client/rest/tx.go | 17 ++++++- 4 files changed, 99 insertions(+), 35 deletions(-) diff --git a/x/cdp/client/rest/query.go b/x/cdp/client/rest/query.go index 7503affb..a92510ce 100644 --- a/x/cdp/client/rest/query.go +++ b/x/cdp/client/rest/query.go @@ -4,14 +4,12 @@ import ( "fmt" "net/http" + "github.com/cosmos/cosmos-sdk/client/context" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/rest" "github.com/gorilla/mux" - "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/types/rest" - "github.com/kava-labs/kava/x/cdp/types" - - sdk "github.com/cosmos/cosmos-sdk/types" ) // define routes that get registered by the main application @@ -25,11 +23,11 @@ func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router) { func queryCdpHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - // Parse the query height cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) if !ok { return } + vars := mux.Vars(r) ownerBech32 := vars[types.RestOwner] collateralDenom := vars[types.RestCollateralDenom] @@ -44,7 +42,7 @@ func queryCdpHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { bz, err := cliCtx.Codec.MarshalJSON(params) if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal query params: %s", err)) return } @@ -56,17 +54,16 @@ func queryCdpHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { cliCtx = cliCtx.WithHeight(height) rest.PostProcessResponse(w, cliCtx, res) - } } func queryCdpsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - // Parse the query height cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) if !ok { return } + vars := mux.Vars(r) collateralDenom := vars[types.RestCollateralDenom] @@ -74,7 +71,7 @@ func queryCdpsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { bz, err := cliCtx.Codec.MarshalJSON(params) if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal query params: %s", err)) return } @@ -86,17 +83,16 @@ func queryCdpsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { cliCtx = cliCtx.WithHeight(height) rest.PostProcessResponse(w, cliCtx, res) - } } func queryCdpsByRatioHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - // Parse the query height cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) if !ok { return } + vars := mux.Vars(r) collateralDenom := vars[types.RestCollateralDenom] ratioStr := vars[types.RestRatio] @@ -110,7 +106,7 @@ func queryCdpsByRatioHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { params := types.NewQueryCdpsByRatioParams(collateralDenom, ratioDec) bz, err := cliCtx.Codec.MarshalJSON(params) if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal query params: %s", err)) return } @@ -122,17 +118,16 @@ func queryCdpsByRatioHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { cliCtx = cliCtx.WithHeight(height) rest.PostProcessResponse(w, cliCtx, res) - } } func queryCdpDepositsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - // Parse the query height cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) if !ok { return } + vars := mux.Vars(r) ownerBech32 := vars[types.RestOwner] collateralDenom := vars[types.RestCollateralDenom] @@ -147,7 +142,7 @@ func queryCdpDepositsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { bz, err := cliCtx.Codec.MarshalJSON(params) if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal query params: %s", err)) return } @@ -159,25 +154,23 @@ func queryCdpDepositsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { cliCtx = cliCtx.WithHeight(height) rest.PostProcessResponse(w, cliCtx, res) - } } func getParamsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - // Parse the query height cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) if !ok { return } - // Get the params + res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/cdp/%s", types.QueryGetParams), nil) cliCtx = cliCtx.WithHeight(height) if err != nil { rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } - // Return the params + rest.PostProcessResponse(w, cliCtx, res) } } diff --git a/x/cdp/client/rest/tx.go b/x/cdp/client/rest/tx.go index 500e688e..ec418f55 100644 --- a/x/cdp/client/rest/tx.go +++ b/x/cdp/client/rest/tx.go @@ -1,14 +1,15 @@ package rest import ( + "bytes" + "fmt" "net/http" - "github.com/gorilla/mux" - "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + "github.com/gorilla/mux" "github.com/kava-labs/kava/x/cdp/types" ) @@ -24,110 +25,163 @@ func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router) { func postCdpHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - // Decode PUT request body var requestBody PostCdpReq if !rest.ReadRESTReq(w, r, cliCtx.Codec, &requestBody) { return } + requestBody.BaseReq = requestBody.BaseReq.Sanitize() if !requestBody.BaseReq.ValidateBasic(w) { return } - // Create and return msg + fromAddr, err := sdk.AccAddressFromBech32(requestBody.BaseReq.From) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + if !bytes.Equal(fromAddr, requestBody.Sender) { + rest.WriteErrorResponse(w, http.StatusUnauthorized, fmt.Sprintf("expected: %s, got: %s", fromAddr, requestBody.Sender)) + return + } + msg := types.NewMsgCreateCDP( requestBody.Sender, requestBody.Collateral, requestBody.Principal, ) + if err := msg.ValidateBasic(); err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + utils.WriteGenerateStdTxResponse(w, cliCtx, requestBody.BaseReq, []sdk.Msg{msg}) } } func postDepositHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - // Decode PUT request body var requestBody PostDepositReq if !rest.ReadRESTReq(w, r, cliCtx.Codec, &requestBody) { return } + requestBody.BaseReq = requestBody.BaseReq.Sanitize() if !requestBody.BaseReq.ValidateBasic(w) { return } - // Create and return msg msg := types.NewMsgDeposit( requestBody.Owner, requestBody.Depositor, requestBody.Collateral, ) + if err := msg.ValidateBasic(); err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + utils.WriteGenerateStdTxResponse(w, cliCtx, requestBody.BaseReq, []sdk.Msg{msg}) } } func postWithdrawHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - // Decode PUT request body var requestBody PostWithdrawalReq if !rest.ReadRESTReq(w, r, cliCtx.Codec, &requestBody) { return } + requestBody.BaseReq = requestBody.BaseReq.Sanitize() if !requestBody.BaseReq.ValidateBasic(w) { return } - // Create and return msg msg := types.NewMsgWithdraw( requestBody.Owner, requestBody.Depositor, requestBody.Collateral, ) + if err := msg.ValidateBasic(); err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + utils.WriteGenerateStdTxResponse(w, cliCtx, requestBody.BaseReq, []sdk.Msg{msg}) } } func postDrawHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - // Decode PUT request body var requestBody PostDrawReq if !rest.ReadRESTReq(w, r, cliCtx.Codec, &requestBody) { return } + requestBody.BaseReq = requestBody.BaseReq.Sanitize() if !requestBody.BaseReq.ValidateBasic(w) { return } - // Create and return msg + fromAddr, err := sdk.AccAddressFromBech32(requestBody.BaseReq.From) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + if !bytes.Equal(fromAddr, requestBody.Owner) { + rest.WriteErrorResponse(w, http.StatusUnauthorized, fmt.Sprintf("expected: %s, got: %s", fromAddr, requestBody.Owner)) + return + } + msg := types.NewMsgDrawDebt( requestBody.Owner, requestBody.Denom, requestBody.Principal, ) + if err := msg.ValidateBasic(); err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + utils.WriteGenerateStdTxResponse(w, cliCtx, requestBody.BaseReq, []sdk.Msg{msg}) } } func postRepayHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - // Decode PUT request body var requestBody PostRepayReq if !rest.ReadRESTReq(w, r, cliCtx.Codec, &requestBody) { return } + requestBody.BaseReq = requestBody.BaseReq.Sanitize() if !requestBody.BaseReq.ValidateBasic(w) { return } - // Create and return msg + fromAddr, err := sdk.AccAddressFromBech32(requestBody.BaseReq.From) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + if !bytes.Equal(fromAddr, requestBody.Owner) { + rest.WriteErrorResponse(w, http.StatusUnauthorized, fmt.Sprintf("expected: %s, got: %s", fromAddr, requestBody.Owner)) + return + } + msg := types.NewMsgRepayDebt( requestBody.Owner, requestBody.Denom, requestBody.Payment, ) + if err := msg.ValidateBasic(); err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + utils.WriteGenerateStdTxResponse(w, cliCtx, requestBody.BaseReq, []sdk.Msg{msg}) } } diff --git a/x/incentive/client/rest/query.go b/x/incentive/client/rest/query.go index 27a41ffc..50921ea9 100644 --- a/x/incentive/client/rest/query.go +++ b/x/incentive/client/rest/query.go @@ -29,6 +29,7 @@ func queryClaimsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { if !ok { return } + vars := mux.Vars(r) ownerBech32 := vars[types.RestClaimOwner] denom := vars[types.RestClaimDenom] @@ -42,17 +43,18 @@ func queryClaimsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { queryParams := types.NewQueryClaimsParams(owner, denom) bz, err := cliCtx.Codec.MarshalJSON(queryParams) if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("failed to marshal query params: %s", err)) return } + res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/incentive/%s", types.QueryGetClaims), bz) if err != nil { rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) return } + cliCtx = cliCtx.WithHeight(height) rest.PostProcessResponse(w, cliCtx, res) - } } diff --git a/x/incentive/client/rest/tx.go b/x/incentive/client/rest/tx.go index 34b2aa96..9d7ff49d 100644 --- a/x/incentive/client/rest/tx.go +++ b/x/incentive/client/rest/tx.go @@ -1,6 +1,8 @@ package rest import ( + "bytes" + "fmt" "net/http" "github.com/gorilla/mux" @@ -15,7 +17,6 @@ import ( func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router) { r.HandleFunc("/incentive/claim", postClaimHandlerFn(cliCtx)).Methods("POST") - } func postClaimHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { @@ -24,15 +25,29 @@ func postClaimHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { if !rest.ReadRESTReq(w, r, cliCtx.Codec, &requestBody) { return } + requestBody.BaseReq = requestBody.BaseReq.Sanitize() if !requestBody.BaseReq.ValidateBasic(w) { return } + + fromAddr, err := sdk.AccAddressFromBech32(requestBody.BaseReq.From) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + if !bytes.Equal(fromAddr, requestBody.Sender) { + rest.WriteErrorResponse(w, http.StatusUnauthorized, fmt.Sprintf("expected: %s, got: %s", fromAddr, requestBody.Sender)) + return + } + msg := types.NewMsgClaimReward(requestBody.Sender, requestBody.Denom) if err := msg.ValidateBasic(); err != nil { rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) return } + utils.WriteGenerateStdTxResponse(w, cliCtx, requestBody.BaseReq, []sdk.Msg{msg}) } }