Skip to content

Commit 8518a01

Browse files
authored
fix: explicit /exapps/ in NGINX example; don't blacklist trusted callers (#100)
Signed-off-by: Oleksander Piskun <oleksandr2088@icloud.com>
1 parent 31c6b9b commit 8518a01

2 files changed

Lines changed: 19 additions & 5 deletions

File tree

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ server {
115115
server_name nextcloud.com;
116116
117117
location /exapps/ {
118-
proxy_pass http://127.0.0.1:8780;
118+
proxy_pass http://127.0.0.1:8780/exapps/;
119119
proxy_set_header Host $host;
120120
proxy_set_header X-Real-IP $remote_addr;
121121
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
@@ -515,13 +515,13 @@ docker run \
515515
4. Create folder `dev` at the root of repository, extract there content of the desired archive with the [FRP](https://github.com/fatedier/frp/releases/latest) archive which is located at `exapps_dev` folder of this repo.
516516
5. Edit the `data/nginx/vhost.d/nextcloud.local_location` file from the `nextcloud-docker-dev` to point `/exapps/` web route to the host:
517517
```
518-
proxy_pass http://172.17.0.1:8780;
518+
proxy_pass http://172.17.0.1:8780/exapps/;
519519
```
520520
521521
> **Note:** my original content from my dev machine of file `nextcloud.local_location`:
522522
> ```nginx
523523
> location /exapps/ {
524-
> proxy_pass http://172.17.0.1:8780;
524+
> proxy_pass http://172.17.0.1:8780/exapps/;
525525
> }
526526
> ```
527527
6. Use `docker compose up -d --force-recreate proxy` command from Julius `nextcloud-docker-dev` to recreate the proxy container.

haproxy_agent.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,20 @@ async def record_ip_failure(ip_address: str | IPv4Address | IPv6Address) -> None
310310
LOGGER.warning("Recorded failure for IP %s. Failures in window: %d", ip_str, len(attempts))
311311

312312

313+
async def record_failure_unless_trusted(
314+
ip_address: str | IPv4Address | IPv6Address, request_headers: dict[str, str]
315+
) -> None:
316+
"""Record a blacklist failure unless the request is authenticated with a valid harp-shared-key.
317+
318+
Requests from Nextcloud/AppAPI carry `harp-shared-key` matching `SHARED_KEY`; a misconfiguration
319+
on that trusted path (e.g. reverse-proxy stripping `/exapps/`) would otherwise cause the caller
320+
to self-DoS once the blacklist window fills up.
321+
"""
322+
if request_headers.get("harp-shared-key") == SHARED_KEY:
323+
return
324+
await record_ip_failure(ip_address)
325+
326+
313327
async def is_ip_banned(ip_address: str | IPv4Address | IPv6Address) -> bool:
314328
"""Return True if IP has exceeded the maximum allowed failures in the request window."""
315329
ip_str = str(ip_address)
@@ -375,7 +389,7 @@ async def exapps_msg(
375389
match = APPID_PATTERN.search(path)
376390
if not match:
377391
LOGGER.error("Invalid request path, cannot find AppID: %s", path)
378-
await record_ip_failure(client_ip_str)
392+
await record_failure_unless_trusted(client_ip_str, request_headers)
379393
return reply.set_txn_var("not_found", 1)
380394
exapp_id = match.group(1)
381395
exapp_id_lower = exapp_id.lower()
@@ -424,7 +438,7 @@ async def exapps_msg(
424438
exapp_record = await _get_or_fetch_exapp(exapp_id_lower)
425439
if not exapp_record:
426440
LOGGER.error("No such ExApp enabled: %s", exapp_id)
427-
await record_ip_failure(client_ip_str)
441+
await record_failure_unless_trusted(client_ip_str, request_headers)
428442
return reply.set_txn_var("not_found", 1)
429443
except ValidationError as e:
430444
LOGGER.error("Invalid ExApp metadata from Nextcloud: %s", e)

0 commit comments

Comments
 (0)