diff --git a/pollbot/pollbot/http.go b/pollbot/pollbot/http.go index 34713397..ba862b73 100644 --- a/pollbot/pollbot/http.go +++ b/pollbot/pollbot/http.go @@ -87,21 +87,31 @@ func (h *HTTPSrv) handleVote(w http.ResponseWriter, r *http.Request) { return } vstr := r.URL.Query().Get("") - vote := NewVoteFromEncoded(vstr) - // WithoutCancel: the browser submits the vote and may close the connection; - // DB writes and poll result updates must complete regardless. - ctx := context.WithoutCancel(r.Context()) - if err := h.db.CastVote(ctx, username, vote); err != nil { - h.Errorf("failed to cast vote: %s", err) + vote, err := NewVoteFromEncoded(vstr) + if err != nil { + h.Debug("invalid vote payload: %s", err) h.showError(w) return } + // WithoutCancel: the browser submits the vote and may close the connection; + // DB writes and poll result updates must complete regardless. + ctx := context.WithoutCancel(r.Context()) convID, resultMsgID, numChoices, err := h.db.GetPollInfo(ctx, vote.ID) if err != nil { h.Errorf("failed to find poll result msg: %s", err) h.showError(w) return } + if vote.Choice < 1 || vote.Choice > numChoices { + h.Debug("vote choice %d out of range for poll %q", vote.Choice, vote.ID) + h.showError(w) + return + } + if err := h.db.CastVote(ctx, username, vote); err != nil { + h.Errorf("failed to cast vote: %s", err) + h.showError(w) + return + } tally, err := h.db.GetTally(ctx, vote.ID) if err != nil { h.Errorf("failed to get tally: %s", err) diff --git a/pollbot/pollbot/vote.go b/pollbot/pollbot/vote.go index 1c3f2fb5..ae7ff5b1 100644 --- a/pollbot/pollbot/vote.go +++ b/pollbot/pollbot/vote.go @@ -1,6 +1,8 @@ package pollbot import ( + "fmt" + "github.com/keybase/managed-bots/base" ) @@ -21,11 +23,19 @@ func NewVote(id string, choice int) Vote { } } -func NewVoteFromEncoded(sdat string) Vote { +func NewVoteFromEncoded(sdat string) (Vote, error) { var ve voteToEncode - dat, _ := base.URLEncoder().DecodeString(sdat) - _ = base.MsgpackDecode(&ve, dat) - return Vote(ve) + dat, err := base.URLEncoder().DecodeString(sdat) + if err != nil { + return Vote{}, err + } + if err := base.MsgpackDecode(&ve, dat); err != nil { + return Vote{}, err + } + if ve.ID == "" { + return Vote{}, fmt.Errorf("missing poll id") + } + return Vote(ve), nil } func (v Vote) Encode() string {