carlos / platform Public

console: key the CLI write-door rate limit by address, not token

Corrects the previous fix: s.cli.write is keyed by ADDRESS at its existing
call site (handleCLINewAccount), and the promote/rollback handlers keyed it
by token hash instead — two incompatible key spaces sharing one limiter map,
and a developer with several live tokens got an independent write budget per
token rather than one budget for the person. Both handlers now key on addr
from apiAccountApp, matching handleCLINewAccount exactly.
Paul Campbell 40e1292422d0f2368615496a362a4829ac3d70a7 parent 6abb2ff
1 file changed, +14 −8
  • internal/console/apicli.go +14 −8
diff --git a/internal/console/apicli.go b/internal/console/apicli.go
index accb23fa7..e6d4f7a39 100644
--- a/internal/console/apicli.go
+++ b/internal/console/apicli.go
@@ -186,10 +186,13 @@ func (s *Server) handleAPIPromote(w http.ResponseWriter, r *http.Request) {
if !ok {
return
}
- // Keyed on the TOKEN, not the client IP (design §3): a token is the
- // natural principal for a write a bearer credential is already
- // authenticating, the same choice handleCLINewAccount makes.
- if !s.cli.write.allow(hashToken(bearer(r)), time.Now()) {
+ // Keyed on the ADDRESS, not the token: the principal a write budget
+ // belongs to is the PERSON, not the terminal they happen to be typing on
+ // — the same key handleCLINewAccount already uses on this limiter.
+ // Keying by token instead would give someone with several live tokens an
+ // independent budget per token, which is the limit doing less than it
+ // should, not more.
+ if !s.cli.write.allow(addr, time.Now()) {
jsonError(w, http.StatusTooManyRequests, "too many requests — wait a minute and try again")
return
}
@@ -271,10 +274,13 @@ func (s *Server) handleAPIRollback(w http.ResponseWriter, r *http.Request) {
if !ok {
return
}
- // Keyed on the TOKEN, not the client IP (design §3): a token is the
- // natural principal for a write a bearer credential is already
- // authenticating, the same choice handleCLINewAccount makes.
- if !s.cli.write.allow(hashToken(bearer(r)), time.Now()) {
+ // Keyed on the ADDRESS, not the token: the principal a write budget
+ // belongs to is the PERSON, not the terminal they happen to be typing on
+ // — the same key handleCLINewAccount already uses on this limiter.
+ // Keying by token instead would give someone with several live tokens an
+ // independent budget per token, which is the limit doing less than it
+ // should, not more.
+ if !s.cli.write.allow(addr, time.Now()) {
jsonError(w, http.StatusTooManyRequests, "too many requests — wait a minute and try again")
return
}