Skip to content

Commit

Permalink
added generic search validation mechanism
Browse files Browse the repository at this point in the history
  • Loading branch information
remoterami committed Oct 22, 2024
1 parent c364333 commit c0adbb1
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 19 deletions.
2 changes: 1 addition & 1 deletion backend/pkg/api/data_access/dummy.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ func (d *DummyService) GetValidatorDashboardDuties(ctx context.Context, dashboar
return getDummyWithPaging[t.VDBEpochDutiesTableRow]()
}

func (d *DummyService) GetValidatorDashboardBlocks(ctx context.Context, dashboardId t.VDBId, cursor string, colSort t.Sort[enums.VDBBlocksColumn], search string, limit uint64, protocolModes t.VDBProtocolModes) ([]t.VDBBlocksTableRow, *t.Paging, error) {
func (d *DummyService) GetValidatorDashboardBlocks(ctx context.Context, dashboardId t.VDBId, cursor string, colSort t.Sort[enums.VDBBlocksColumn], search enums.VDBBlocksSearches, limit uint64, protocolModes t.VDBProtocolModes) ([]t.VDBBlocksTableRow, *t.Paging, error) {
return getDummyWithPaging[t.VDBBlocksTableRow]()
}

Expand Down
2 changes: 1 addition & 1 deletion backend/pkg/api/data_access/vdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ type ValidatorDashboardRepository interface {

GetValidatorDashboardDuties(ctx context.Context, dashboardId t.VDBId, epoch uint64, groupId int64, cursor string, colSort t.Sort[enums.VDBDutiesColumn], search string, limit uint64, protocolModes t.VDBProtocolModes) ([]t.VDBEpochDutiesTableRow, *t.Paging, error)

GetValidatorDashboardBlocks(ctx context.Context, dashboardId t.VDBId, cursor string, colSort t.Sort[enums.VDBBlocksColumn], search string, limit uint64, protocolModes t.VDBProtocolModes) ([]t.VDBBlocksTableRow, *t.Paging, error)
GetValidatorDashboardBlocks(ctx context.Context, dashboardId t.VDBId, cursor string, colSort t.Sort[enums.VDBBlocksColumn], search enums.VDBBlocksSearches, limit uint64, protocolModes t.VDBProtocolModes) ([]t.VDBBlocksTableRow, *t.Paging, error)

GetValidatorDashboardHeatmap(ctx context.Context, dashboardId t.VDBId, protocolModes t.VDBProtocolModes, aggregation enums.ChartAggregation, afterTs uint64, beforeTs uint64) (*t.VDBHeatmap, error)
GetValidatorDashboardGroupHeatmap(ctx context.Context, dashboardId t.VDBId, groupId uint64, protocolModes t.VDBProtocolModes, aggregation enums.ChartAggregation, timestamp uint64) (*t.VDBHeatmapTooltipData, error)
Expand Down
26 changes: 10 additions & 16 deletions backend/pkg/api/data_access/vdb_blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"database/sql"
"fmt"
"regexp"
"slices"
"strings"
"time"
Expand All @@ -20,7 +19,7 @@ import (
"github.com/shopspring/decimal"
)

func (d *DataAccessService) GetValidatorDashboardBlocks(ctx context.Context, dashboardId t.VDBId, cursor string, colSort t.Sort[enums.VDBBlocksColumn], search string, limit uint64, protocolModes t.VDBProtocolModes) ([]t.VDBBlocksTableRow, *t.Paging, error) {
func (d *DataAccessService) GetValidatorDashboardBlocks(ctx context.Context, dashboardId t.VDBId, cursor string, colSort t.Sort[enums.VDBBlocksColumn], search enums.VDBBlocksSearches, limit uint64, protocolModes t.VDBProtocolModes) ([]t.VDBBlocksTableRow, *t.Paging, error) {
// @DATA-ACCESS incorporate protocolModes
var err error
var currentCursor t.BlocksCursor
Expand All @@ -32,11 +31,6 @@ func (d *DataAccessService) GetValidatorDashboardBlocks(ctx context.Context, das
}
}

// regexes taken from api handler common.go
searchPubkey := regexp.MustCompile(`^0x[0-9a-fA-F]{96}$`).MatchString(search)
searchGroup := regexp.MustCompile(`^[a-zA-Z0-9_\-.\ ]+$`).MatchString(search)
searchIndex := regexp.MustCompile(`^[0-9]+$`).MatchString(search)

validatorMap := make(map[t.VDBValidator]bool)
params := []interface{}{}
filteredValidatorsQuery := ""
Expand Down Expand Up @@ -66,18 +60,18 @@ func (d *DataAccessService) GetValidatorDashboardBlocks(ctx context.Context, das
from := `FROM users_val_dashboards_validators validators `
where := `WHERE validators.dashboard_id = $1`
extraConds := make([]string, 0, 3)
if searchIndex {
params = append(params, search)
if search.Index {
params = append(params, search.Value)
extraConds = append(extraConds, fmt.Sprintf(`validator_index = $%d`, len(params)))
}
if searchGroup {
if search.Group {
from += `INNER JOIN users_val_dashboards_groups groups ON validators.dashboard_id = groups.dashboard_id AND validators.group_id = groups.id `
// escape the psql single character wildcard "_"; apply prefix-search
params = append(params, strings.Replace(search, "_", "\\_", -1)+"%")
params = append(params, strings.Replace(search.Value, "_", "\\_", -1)+"%")
extraConds = append(extraConds, fmt.Sprintf(`LOWER(name) LIKE LOWER($%d)`, len(params)))
}
if searchPubkey {
index, ok := validatorMapping.ValidatorIndices[search]
if search.PublicKey {
index, ok := validatorMapping.ValidatorIndices[search.Value]
if !ok && len(extraConds) == 0 {
// don't even need to query
return make([]t.VDBBlocksTableRow, 0), &t.Paging{}, nil
Expand All @@ -93,13 +87,13 @@ func (d *DataAccessService) GetValidatorDashboardBlocks(ctx context.Context, das
} else {
validators := make([]t.VDBValidator, 0, len(dashboardId.Validators))
for _, validator := range dashboardId.Validators {
if searchIndex && fmt.Sprint(validator) != search ||
searchPubkey && validator != validatorMapping.ValidatorIndices[search] {
if search.Index && fmt.Sprint(validator) != search.Value ||
search.PublicKey && validator != validatorMapping.ValidatorIndices[search.Value] {
continue
}
validatorMap[validator] = true
validators = append(validators, validator)
if searchIndex || searchPubkey {
if search.Index || search.PublicKey {
break
}
}
Expand Down
48 changes: 48 additions & 0 deletions backend/pkg/api/enums/enums.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,54 @@ func IsInvalidEnum(e Enum) bool {
return e.Int() == -1
}

type SearchType int

// all possible search types
const (
Name SearchType = iota // default
Integer
EthereumAddress
WithdrawalCredential
EnsName
NonEmpty
Graffiti
Cursor
Email
Password
EmailUserToken
JsonContentType
// Validator Dashboard
ValidatorDashboardPublicId
ValidatorPublicKeyWithPrefix
ValidatorPublicKey
)

var InvalidSearch = Searchable(nil)

type Searchable interface {
GetSearches() []SearchType
// return if successful
SetSearchType(st SearchType, b bool) Searchable
SetSearchValue(s string) Searchable
}

type BasicSearch struct {
Value string // searched string
}

func (bs BasicSearch) SetSearchValue(s string) Searchable {
bs.Value = s
return bs
}

func (bs BasicSearch) GetSearches() []SearchType {
return []SearchType{}
}

func (bs BasicSearch) SetSearchType(st SearchType, b bool) Searchable {
return bs
}

type AdInsertMode int

var _ EnumFactory[AdInsertMode] = AdInsertMode(0)
Expand Down
29 changes: 29 additions & 0 deletions backend/pkg/api/enums/validator_dashboard_enums.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,35 @@ var VDBBlocksColumns = struct {
VDBBlockProposerReward,
}

type VDBBlocksSearches struct {
BasicSearch
Index bool
PublicKey bool
Group bool
}

func (s VDBBlocksSearches) GetSearches() []SearchType {
return []SearchType{
Integer,
ValidatorPublicKeyWithPrefix,
Name,
}
}

func (s VDBBlocksSearches) SetSearchType(st SearchType, b bool) Searchable {
switch st {
case Integer:
s.Index = b
case ValidatorPublicKeyWithPrefix:
s.PublicKey = b
case Name:
s.Group = b
default:
return InvalidSearch
}
return s
}

// ----------------
// Validator Dashboard Withdrawals Table

Expand Down
30 changes: 30 additions & 0 deletions backend/pkg/api/handlers/input_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,25 @@ var (
reJsonContentType = regexp.MustCompile(`^application\/json(;.*)?$`)
)

var searchEnumsRegexMapping = map[enums.SearchType]*regexp.Regexp{
enums.Name: reName,
enums.Integer: reInteger,
enums.EthereumAddress: reEthereumAddress,
enums.WithdrawalCredential: reWithdrawalCredential,
enums.EnsName: reEnsName,
enums.NonEmpty: reNonEmpty,
enums.Graffiti: reGraffiti,
enums.Cursor: reCursor,
enums.Email: reEmail,
enums.Password: rePassword,
enums.EmailUserToken: reEmailUserToken,
enums.JsonContentType: reJsonContentType,
// Validator Dashboard
enums.ValidatorDashboardPublicId: reValidatorDashboardPublicId,
enums.ValidatorPublicKeyWithPrefix: reValidatorPublicKeyWithPrefix,
enums.ValidatorPublicKey: reValidatorPublicKey,
}

const (
maxNameLength = 50
maxValidatorsInList = 20
Expand Down Expand Up @@ -416,6 +435,17 @@ func checkSort[T enums.EnumFactory[T]](v *validationError, sortString string) *t
return &types.Sort[T]{Column: sortCol, Desc: desc}
}

func checkSearch[T enums.Searchable](searchString string) (T, error) {
var search T
for _, acceptedSearchType := range search.GetSearches() {
if search := search.SetSearchType(acceptedSearchType, searchEnumsRegexMapping[acceptedSearchType].MatchString(searchString)); search == enums.InvalidSearch {
return search.(T), newInternalServerErr("Error setting search request")
}
}
search.SetSearchValue(searchString)
return search, nil
}

func (v *validationError) checkProtocolModes(protocolModes string) types.VDBProtocolModes {
var modes types.VDBProtocolModes
if protocolModes == "" {
Expand Down
7 changes: 6 additions & 1 deletion backend/pkg/api/handlers/public.go
Original file line number Diff line number Diff line change
Expand Up @@ -1391,8 +1391,13 @@ func (h *HandlerService) PublicGetValidatorDashboardBlocks(w http.ResponseWriter
handleErr(w, r, v)
return
}
search, err := checkSearch[enums.VDBBlocksSearches](pagingParams.search)
if err != nil {
handleErr(w, r, v)
return
}

data, paging, err := h.getDataAccessor(r).GetValidatorDashboardBlocks(r.Context(), *dashboardId, pagingParams.cursor, *sort, pagingParams.search, pagingParams.limit, protocolModes)
data, paging, err := h.getDataAccessor(r).GetValidatorDashboardBlocks(r.Context(), *dashboardId, pagingParams.cursor, *sort, search, pagingParams.limit, protocolModes)
if err != nil {
handleErr(w, r, err)
return
Expand Down

0 comments on commit c0adbb1

Please sign in to comment.