metricq / aiocouch

🛋 An asynchronous client library for CouchDB 2.x and 3.x
https://aiocouch.readthedocs.io/en/latest/
BSD 3-Clause "New" or "Revised" License
29 stars 10 forks source link

feat: Handle CouchDB HTTP 403 on all routes #56

Open H--o-l opened 1 month ago

H--o-l commented 1 month ago

Since CouchDB v3.4.0, there has been a new "Lockout" feature, i.e., a rate limit on tuples (IP, login) after multiple authentication failures. It's highlighted in the release note: https://docs.couchdb.org/en/stable/whatsnew/3.4.html#id4 (see the second to last bullet point).

As the following upstream discussion shows, this CouchDB feature adds a new case of HTTP 403 possible on all routes: https://github.com/apache/couchdb/issues/5315#issuecomment-2427009998

This commit catches the 403 on all routes. As some routes were already catching 403 for other reasons, the exception message on these routes is changed from their previous message to "Access forbidden: {reason}" where reason is either the reason returned by CouchDB in the JSON body of the answer, or if it doesn't exist, by the message of aiohttp ClientResponseError.

I manually tested a non-stream route with await couchdb.info(), it returns the following:

> await couchdb.info()
...
aiocouch.exception.UnauthorizedError: Invalid credentials
> await couchdb.info()  # <=== Lockout
...
aiocouch.exception.ForbiddenError: Access forbidden: Account is temporarily
locked due to multiple authentication failures