lib/api: Fix and optimize csrfManager (#8329)
An off-by-one error could cause tokens to be forgotten. Suppose
tokens := []string{"foo", "bar", "baz", "quux"}
i := 2
token := tokens[i] // token == "baz"
Then, after
copy(tokens[1:], tokens[:i+1])
tokens[0] = token
we have
tokens == []string{"baz", "foo", "bar", "baz"}
The short test actually relied on this bug.
This commit is contained in:
+8
-5
@@ -46,6 +46,7 @@ type apiKeyValidator interface {
|
||||
func newCsrfManager(unique string, prefix string, apiKeyValidator apiKeyValidator, next http.Handler, saveLocation string) *csrfManager {
|
||||
m := &csrfManager{
|
||||
tokensMut: sync.NewMutex(),
|
||||
tokens: make([]string, 0, maxCsrfTokens),
|
||||
unique: unique,
|
||||
prefix: prefix,
|
||||
apiKeyValidator: apiKeyValidator,
|
||||
@@ -108,7 +109,7 @@ func (m *csrfManager) validToken(token string) bool {
|
||||
// Move this token to the head of the list. Copy the tokens at
|
||||
// the front one step to the right and then replace the token
|
||||
// at the head.
|
||||
copy(m.tokens[1:], m.tokens[:i+1])
|
||||
copy(m.tokens[1:], m.tokens[:i])
|
||||
m.tokens[0] = token
|
||||
}
|
||||
return true
|
||||
@@ -121,12 +122,14 @@ func (m *csrfManager) newToken() string {
|
||||
token := rand.String(32)
|
||||
|
||||
m.tokensMut.Lock()
|
||||
m.tokens = append([]string{token}, m.tokens...)
|
||||
if len(m.tokens) > maxCsrfTokens {
|
||||
m.tokens = m.tokens[:maxCsrfTokens]
|
||||
}
|
||||
defer m.tokensMut.Unlock()
|
||||
|
||||
if len(m.tokens) < maxCsrfTokens {
|
||||
m.tokens = append(m.tokens, "")
|
||||
}
|
||||
copy(m.tokens[1:], m.tokens)
|
||||
m.tokens[0] = token
|
||||
|
||||
m.save()
|
||||
|
||||
return token
|
||||
|
||||
Reference in New Issue
Block a user