Detect vote or response replay/caching

This commit is contained in:
Ian Gulliver
2023-06-03 21:51:07 -07:00
parent 8c8133ff52
commit 3cebbc3425
2 changed files with 22 additions and 6 deletions

View File

@@ -142,6 +142,16 @@ func (c *Candidate) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return return
} }
if time.Since(v.VoteSent).Abs() > 15*time.Second {
http.Error(
w,
fmt.Sprintf("excessive time difference (%.1f seconds); delay, replay, or clock skew", time.Since(v.VoteSent).Seconds()),
http.StatusBadRequest,
)
}
c.resp.ResponseSent = time.Now().UTC()
js = lo.Must(json.Marshal(c.resp)) js = lo.Must(json.Marshal(c.resp))
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")

View File

@@ -24,7 +24,7 @@ type vote struct {
VoterID string `json:"voterID"` VoterID string `json:"voterID"`
LastSeenCandidateID string `json:"lastSeenCandidateID"` LastSeenCandidateID string `json:"lastSeenCandidateID"`
NumPollsSinceChange int `json:"numPollsSinceChange"` NumPollsSinceChange int `json:"numPollsSinceChange"`
// TODO: Add timestamp VoteSent time.Time `json:"voteSent"`
// Used internally by Candidate // Used internally by Candidate
received time.Time received time.Time
@@ -32,7 +32,7 @@ type vote struct {
type voteResponse struct { type voteResponse struct {
CandidateID string `json:"candidateID"` CandidateID string `json:"candidateID"`
// TODO: Add timestamp ResponseSent time.Time `json:"responseSent"`
} }
func NewVoter(url string, signingKey string) *Voter { func NewVoter(url string, signingKey string) *Voter {
@@ -105,6 +105,8 @@ func (v *Voter) poll(update <-chan time.Duration, t *time.Ticker) bool {
} }
func (v *Voter) sendVote() { func (v *Voter) sendVote() {
v.vote.VoteSent = time.Now().UTC()
for _, c := range v.candidates { for _, c := range v.candidates {
c.voteIfNo(&v.vote) c.voteIfNo(&v.vote)
} }
@@ -152,6 +154,10 @@ func (v *Voter) sendVote() {
return return
} }
if time.Since(vr.ResponseSent).Abs() > 15*time.Second {
v.log("excessive time difference (%.1f seconds); delay, replay, or clock skew", time.Since(vr.ResponseSent).Seconds())
}
if vr.CandidateID == v.vote.LastSeenCandidateID { if vr.CandidateID == v.vote.LastSeenCandidateID {
v.vote.NumPollsSinceChange++ v.vote.NumPollsSinceChange++
} else { } else {