Detect vote or response replay/caching
This commit is contained in:
10
candidate.go
10
candidate.go
@@ -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")
|
||||||
|
|||||||
10
voter.go
10
voter.go
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user