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:
greatroar
2022-05-07 12:30:13 +02:00
committed by GitHub
parent 520ca4bcb0
commit 97291c9184
2 changed files with 32 additions and 7 deletions
+8 -5
View File
@@ -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