Skip to content

Commit

Permalink
add confirm finding paid
Browse files Browse the repository at this point in the history
  • Loading branch information
skyargos committed Nov 14, 2023
1 parent e493a5f commit 796581c
Show file tree
Hide file tree
Showing 15 changed files with 1,327 additions and 185 deletions.
16 changes: 16 additions & 0 deletions proto/shentu/bounty/v1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ service Query {
rpc Finding(QueryFindingRequest) returns (QueryFindingResponse) {
option (google.api.http).get = "/shentu/bounty/v1/findings/{finding_id}";
}

// FindingFingerprint queries Finding Fingerprint based on FindingId.
rpc FindingFingerprint(QueryFindingFingerprintRequest) returns (QueryFindingFingerprintResponse) {
option (google.api.http).get = "/shentu/bounty/v1/findings/{finding_id}/fingerprint";
}
}

// QueryHostsRequest is the request type for the Query/Hosts RPC method.
Expand Down Expand Up @@ -113,3 +118,14 @@ message QueryFindingRequest {
message QueryFindingResponse {
Finding finding = 1 [(gogoproto.nullable) = false];
}

// QueryFindingFingerPrint is the request type for the Query/Finding RPC method.
message QueryFindingFingerprintRequest {
// finding_id defines the unique id of the finding.
string finding_id = 1;
}

// QueryFindingFingerPrintResponse is the response type for the Query/Finding RPC method.
message QueryFindingFingerprintResponse {
string fingerprint = 1;
}
17 changes: 16 additions & 1 deletion proto/shentu/bounty/v1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ service Msg {
// ConfirmFinding defines a method for host confirm a finding.
rpc ConfirmFinding(MsgConfirmFinding) returns (MsgConfirmFindingResponse);

// ConfirmFindingPaid defines a method for submitter confirm a finding paid
rpc ConfirmFindingPaid(MsgConfirmFindingPaid) returns (MsgConfirmFindingPaidResponse);

// CloseFinding defines a method for submitter or certifier close a finding
rpc CloseFinding(MsgCloseFinding) returns (MsgCloseFindingResponse);

Expand Down Expand Up @@ -133,12 +136,24 @@ message MsgConfirmFinding {

string finding_id = 1 [(gogoproto.moretags) = "yaml:\"finding_id\""];
string operator_address = 2 [(gogoproto.moretags) = "yaml:\"operator_address\""];
string finger_print = 3 [(gogoproto.moretags) = "yaml:\"finger_print\""];
string fingerprint = 3;
}

// MsgConfirmFindingResponse defines the Msg/AcceptFinding response type.
message MsgConfirmFindingResponse {}

// MsgConfirmFindingPaid defines a message to close a finding to an existing finding.
message MsgConfirmFindingPaid {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;

string finding_id = 1 [(gogoproto.moretags) = "yaml:\"finding_id\""];
string operator_address = 2 [(gogoproto.moretags) = "yaml:\"operator_address\""];
}

// MsgCloseFindingResponse defines the Msg/CloseFinding response type.
message MsgConfirmFindingPaidResponse {}

// MsgCloseFinding defines a message to close a finding to an existing finding.
message MsgCloseFinding {
option (gogoproto.equal) = false;
Expand Down
5 changes: 2 additions & 3 deletions x/bounty/client/cli/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ const (
FlagDetail = "detail"

FlagFindingTitle = "title"
FlagFindingSeverityLevel = "severity-level"
FlagFindingDescription = "desc"
FlagFindingProofOfContent = "poc"
FlagFindingFingerPrint = "fingerPrint,"
FlagFindingAddress = "finding-address"
FlagFindingSeverityLevel = "severity-level"
FlagFindingFingerprint = "fingerprint"
FlagSubmitterAddress = "submitter-address"
)
40 changes: 40 additions & 0 deletions x/bounty/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func GetQueryCmd() *cobra.Command {
GetCmdQueryPrograms(),
GetCmdQueryFinding(),
GetCmdQueryFindings(),
GetCmdQueryFindingFingerPrint(),
)

return bountyQueryCmd
Expand Down Expand Up @@ -247,3 +248,42 @@ $ %s query bounty findings --page=1 --limit=100
flags.AddQueryFlagsToCmd(cmd)
return cmd
}

// GetCmdQueryFindingFingerPrint implements the query finding fingerPrint command.
func GetCmdQueryFindingFingerPrint() *cobra.Command {
cmd := &cobra.Command{
Use: "fingerprint [finding-id]",
Args: cobra.ExactArgs(1),
Short: "Query fingerPrint of a single finding",
Long: strings.TrimSpace(
fmt.Sprintf(`Query fingerPrint for a finding. You can find the finding-id by running "%s query bounty findings".
Example:
$ %s query bounty finding 1
`,
version.AppName, version.AppName,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)

// Query the finding
res, err := queryClient.FindingFingerprint(
cmd.Context(),
&types.QueryFindingFingerprintRequest{
FindingId: args[0],
})
if err != nil {
return err
}

return clientCtx.PrintProto(res)
},
}

flags.AddQueryFlagsToCmd(cmd)
return cmd
}
72 changes: 30 additions & 42 deletions x/bounty/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,11 @@ package cli
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"strings"

"github.com/spf13/cobra"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/version"

"github.com/shentufoundation/shentu/v2/x/bounty/types"
)

Expand Down Expand Up @@ -189,13 +184,13 @@ func NewSubmitFindingCmd() *cobra.Command {
if err != nil {
return err
}
severityLevel, err := cmd.Flags().GetInt32(FlagFindingSeverityLevel)
severityLevel, err := cmd.Flags().GetString(FlagFindingSeverityLevel)
if err != nil {
return err
}
_, ok := types.SeverityLevel_name[severityLevel]
if !ok {
return fmt.Errorf("invalid %s value", FlagFindingSeverityLevel)
byteSeverityLevel, err := types.SeverityLevelFromString(types.NormalizeSeverityLevel(severityLevel))
if err != nil {
return err
}

desc, err := cmd.Flags().GetString(FlagFindingDescription)
Expand All @@ -208,7 +203,7 @@ func NewSubmitFindingCmd() *cobra.Command {
}
hash := sha256.Sum256([]byte(desc + poc + submitAddr.String()))

msg := types.NewMsgSubmitFinding(pid, fid, title, detail, hex.EncodeToString(hash[:]), submitAddr, types.SeverityLevel(severityLevel))
msg := types.NewMsgSubmitFinding(pid, fid, title, detail, hex.EncodeToString(hash[:]), submitAddr, byteSeverityLevel)
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
Expand All @@ -219,7 +214,7 @@ func NewSubmitFindingCmd() *cobra.Command {
cmd.Flags().String(FlagFindingDescription, "", "The finding's description")
cmd.Flags().String(FlagFindingProofOfContent, "", "The finding's proof of content")
cmd.Flags().String(FlagDetail, "", "The finding's detail")
cmd.Flags().Int32(FlagFindingSeverityLevel, 0, "The finding's severity level")
cmd.Flags().String(FlagFindingSeverityLevel, "unspecified", "The finding's severity level")
flags.AddTxFlagsToCmd(cmd)

_ = cmd.MarkFlagRequired(flags.FlagFrom)
Expand Down Expand Up @@ -259,7 +254,11 @@ func NewEditFindingCmd() *cobra.Command {
if err != nil {
return err
}
severityLevel, err := cmd.Flags().GetInt32(FlagFindingSeverityLevel)
severityLevel, err := cmd.Flags().GetString(FlagFindingSeverityLevel)
if err != nil {
return err
}
byteSeverityLevel, err := types.SeverityLevelFromString(types.NormalizeSeverityLevel(severityLevel))
if err != nil {
return err
}
Expand All @@ -275,7 +274,7 @@ func NewEditFindingCmd() *cobra.Command {
hash := sha256.Sum256([]byte(desc + poc + submitAddr.String()))
hashString := hex.EncodeToString(hash[:])

msg := types.NewMsgEditFinding(pid, fid, title, detail, hashString, submitAddr, types.SeverityLevel(severityLevel))
msg := types.NewMsgEditFinding(pid, fid, title, detail, hashString, submitAddr, byteSeverityLevel)
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
Expand All @@ -286,7 +285,7 @@ func NewEditFindingCmd() *cobra.Command {
cmd.Flags().String(FlagFindingDescription, "", "The finding's description")
cmd.Flags().String(FlagFindingProofOfContent, "", "The finding's proof of content")
cmd.Flags().String(FlagDetail, "", "The finding's detail")
cmd.Flags().Int32(FlagFindingSeverityLevel, 0, "The finding's severity level")
cmd.Flags().String(FlagFindingSeverityLevel, "unspecified", "The finding's severity level")
flags.AddTxFlagsToCmd(cmd)

_ = cmd.MarkFlagRequired(flags.FlagFrom)
Expand All @@ -296,45 +295,34 @@ func NewEditFindingCmd() *cobra.Command {
return cmd
}

// NewConfirmFinding implements accept a finding by host.
func NewConfirmFinding() *cobra.Command {
cmd := &cobra.Command{
Use: "confirm-finding [finding-id]",
Use: "confirm-finding [finding id]",
Args: cobra.ExactArgs(1),
Short: "Host confirm a finding",
Long: strings.TrimSpace(
fmt.Sprintf(`Host accept a finding for a program.Meantime, you can also add some comments, which will be encrypted.
Example:
$ %s tx bounty confirm-finding 1 --comment "Looks good to me"
`,
version.AppName,
),
),
RunE: ConfirmFinding,
Short: "release the specific finding",
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
submitAddr := clientCtx.GetFromAddress()
fingerprint, err := cmd.Flags().GetString(FlagFindingFingerprint)
if err != nil {
return err
}
msg := types.NewMsgConfirmFinding(args[0], fingerprint, submitAddr)
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}

cmd.Flags().String(FlagFindingFingerprint, "", "The finding's fingerprint")
flags.AddTxFlagsToCmd(cmd)

_ = cmd.MarkFlagRequired(flags.FlagFrom)
_ = cmd.MarkFlagRequired(FlagFindingFingerprint)

return cmd
}

func ConfirmFinding(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

fingerPrint, err := cmd.Flags().GetString(FlagFindingFingerPrint)

// Get host address
hostAddr := clientCtx.GetFromAddress()
msg := types.NewMsgConfirmFinding(args[0], fingerPrint, hostAddr)

return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
}

func NewCloseFindingCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "close-finding [finding id]",
Expand Down
20 changes: 20 additions & 0 deletions x/bounty/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package keeper

import (
"context"
"crypto/sha256"
"encoding/hex"

"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
Expand Down Expand Up @@ -116,3 +118,21 @@ func (k Keeper) Finding(c context.Context, req *types.QueryFindingRequest) (*typ

return &types.QueryFindingResponse{Finding: finding}, nil
}

func (k Keeper) FindingFingerprint(c context.Context, req *types.QueryFindingFingerprintRequest) (*types.QueryFindingFingerprintResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "invalid request")
}
if len(req.FindingId) == 0 {
return nil, status.Error(codes.InvalidArgument, "finding-id can not be 0")
}

Check warning on line 128 in x/bounty/keeper/grpc_query.go

View check run for this annotation

Codecov / codecov/patch

x/bounty/keeper/grpc_query.go#L122-L128

Added lines #L122 - L128 were not covered by tests

ctx := sdk.UnwrapSDKContext(c)
finding, found := k.GetFinding(ctx, req.FindingId)
if !found {
return nil, status.Errorf(codes.NotFound, "finding %s doesn't exist", req.FindingId)
}

Check warning on line 134 in x/bounty/keeper/grpc_query.go

View check run for this annotation

Codecov / codecov/patch

x/bounty/keeper/grpc_query.go#L130-L134

Added lines #L130 - L134 were not covered by tests

hash := sha256.Sum256(k.cdc.MustMarshal(&finding))
return &types.QueryFindingFingerprintResponse{Fingerprint: hex.EncodeToString(hash[:])}, nil

Check warning on line 137 in x/bounty/keeper/grpc_query.go

View check run for this annotation

Codecov / codecov/patch

x/bounty/keeper/grpc_query.go#L136-L137

Added lines #L136 - L137 were not covered by tests
}
45 changes: 44 additions & 1 deletion x/bounty/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,12 +313,53 @@ func (k msgServer) hostProcess(ctx sdk.Context, msg *types.MsgConfirmFinding) (t
// fingerprint comparison
bz := k.cdc.MustMarshal(&finding)
hash := sha256.Sum256(bz)
if msg.FingerPrint != hex.EncodeToString(hash[:]) {
if msg.Fingerprint != hex.EncodeToString(hash[:]) {
return finding, types.ErrFindingHashInvalid
}

Check warning on line 318 in x/bounty/keeper/msg_server.go

View check run for this annotation

Codecov / codecov/patch

x/bounty/keeper/msg_server.go#L317-L318

Added lines #L317 - L318 were not covered by tests
return finding, nil
}

func (k msgServer) ConfirmFindingPaid(goCtx context.Context, msg *types.MsgConfirmFindingPaid) (*types.MsgConfirmFindingPaidResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

operatorAddr, err := sdk.AccAddressFromBech32(msg.OperatorAddress)
if err != nil {
return nil, err
}

// get finding
finding, ok := k.GetFinding(ctx, msg.FindingId)
if !ok {
return nil, types.ErrFindingNotExists
}

Check warning on line 334 in x/bounty/keeper/msg_server.go

View check run for this annotation

Codecov / codecov/patch

x/bounty/keeper/msg_server.go#L333-L334

Added lines #L333 - L334 were not covered by tests
if finding.Status != types.FindingStatusConfirmed {
return nil, types.ErrFindingStatusInvalid
}

Check warning on line 337 in x/bounty/keeper/msg_server.go

View check run for this annotation

Codecov / codecov/patch

x/bounty/keeper/msg_server.go#L336-L337

Added lines #L336 - L337 were not covered by tests

// check operator: finding owner, certificate
if finding.SubmitterAddress != msg.OperatorAddress && !k.certKeeper.IsBountyAdmin(ctx, operatorAddr) {
return nil, types.ErrFindingOperatorNotAllowed
}

Check warning on line 342 in x/bounty/keeper/msg_server.go

View check run for this annotation

Codecov / codecov/patch

x/bounty/keeper/msg_server.go#L341-L342

Added lines #L341 - L342 were not covered by tests

finding.Status = types.FindingStatusPaid
k.SetFinding(ctx, finding)

ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
types.EventTypeConfirmFindingPaid,
sdk.NewAttribute(types.AttributeKeyFindingID, msg.FindingId),
sdk.NewAttribute(types.AttributeKeyProgramID, finding.ProgramId),
),
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
sdk.NewAttribute(sdk.AttributeKeySender, msg.OperatorAddress),
),
})

return &types.MsgConfirmFindingPaidResponse{}, nil
}

func (k msgServer) CloseFinding(goCtx context.Context, msg *types.MsgCloseFinding) (*types.MsgCloseFindingResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

Expand Down Expand Up @@ -396,6 +437,8 @@ func (k msgServer) ReleaseFinding(goCtx context.Context, msg *types.MsgReleaseFi
if program.AdminAddress != msg.OperatorAddress {
return nil, types.ErrProgramCreatorInvalid
}

Check warning on line 439 in x/bounty/keeper/msg_server.go

View check run for this annotation

Codecov / codecov/patch

x/bounty/keeper/msg_server.go#L438-L439

Added lines #L438 - L439 were not covered by tests
default:
return nil, types.ErrFindingStatusInvalid
}

// check hash
Expand Down
Loading

0 comments on commit 796581c

Please sign in to comment.