BUG: Overly restrictive admin check in /api/dashboard/blocklist-search blocks non-admin users from using the blocklist feature #34

Closed
opened 2026-05-22 18:53:44 +01:00 by Gandalf · 1 comment
Owner

Summary

The authorization checks inside server/routes/dashboard.js for the /blocklist-search endpoint are overly restrictive. While DownloadAssembler.canBlocklist calculates if a specific download can be blocklisted by a regular user (e.g., when it has import issues or if it is a torrent over 1 hour old with <100% availability), the route handler POST /api/dashboard/blocklist-search unconditionally rejects any non-admin request with a 403 Forbidden status.

Root Cause

In server/routes/dashboard.js (lines 675-678), the router includes an explicit admin-only gate:

    const user = req.user;
    if (!user.isAdmin) {
      return res.status(403).json({ error: 'Admin access required' });
    }

This check completely overrides the granular permissions evaluated by DownloadAssembler.canBlocklist(download, isAdmin), which are used by DownloadMatcher.js to expose the "Blocklist + Re-search" button to non-admin users.

Impact

When a non-admin user has a download that qualifies for blocklisting (e.g., it has an import issue), they are correctly shown the "Blocklist + Re-search" button in their dashboard interface. However, clicking the button triggers a request to POST /api/dashboard/blocklist-search, which immediately fails with a 403 Forbidden error. This creates a severe mismatch between UI capability states and backend enforcement, resulting in a broken user experience.

Steps to Reproduce

  1. Log in as a non-admin user.
  2. Trigger or observe a download that fails with an import issue (so that DownloadAssembler.canBlocklist evaluates to true).
  3. The dashboard UI correctly renders the "Blocklist + Re-search" button.
  4. Click the button.
  5. The request to /api/dashboard/blocklist-search fails with a 403 Forbidden: Admin access required status code.

Proposed Fix

Modify POST /api/dashboard/blocklist-search to dynamically authorize non-admin users:

  1. If the user is an admin, always authorize the operation.
  2. If the user is NOT an admin, retrieve the target download object (e.g., from the active download cache or active queue) using the request parameters.
  3. Validate that the download belongs to the requesting user.
  4. Call DownloadAssembler.canBlocklist(download, false) to verify if they are authorized to blocklist it.
  5. Proceed with the blocklist and search command if authorized; otherwise, return a 403 Forbidden error.
### Summary The authorization checks inside `server/routes/dashboard.js` for the `/blocklist-search` endpoint are overly restrictive. While `DownloadAssembler.canBlocklist` calculates if a specific download can be blocklisted by a regular user (e.g., when it has import issues or if it is a torrent over 1 hour old with <100% availability), the route handler `POST /api/dashboard/blocklist-search` unconditionally rejects any non-admin request with a `403 Forbidden` status. ### Root Cause In `server/routes/dashboard.js` (lines 675-678), the router includes an explicit admin-only gate: ```javascript const user = req.user; if (!user.isAdmin) { return res.status(403).json({ error: 'Admin access required' }); } ``` This check completely overrides the granular permissions evaluated by `DownloadAssembler.canBlocklist(download, isAdmin)`, which are used by `DownloadMatcher.js` to expose the "Blocklist + Re-search" button to non-admin users. ### Impact When a non-admin user has a download that qualifies for blocklisting (e.g., it has an import issue), they are correctly shown the "Blocklist + Re-search" button in their dashboard interface. However, clicking the button triggers a request to `POST /api/dashboard/blocklist-search`, which immediately fails with a `403 Forbidden` error. This creates a severe mismatch between UI capability states and backend enforcement, resulting in a broken user experience. ### Steps to Reproduce 1. Log in as a non-admin user. 2. Trigger or observe a download that fails with an import issue (so that `DownloadAssembler.canBlocklist` evaluates to true). 3. The dashboard UI correctly renders the "Blocklist + Re-search" button. 4. Click the button. 5. The request to `/api/dashboard/blocklist-search` fails with a `403 Forbidden: Admin access required` status code. ### Proposed Fix Modify `POST /api/dashboard/blocklist-search` to dynamically authorize non-admin users: 1. If the user is an admin, always authorize the operation. 2. If the user is NOT an admin, retrieve the target download object (e.g., from the active download cache or active queue) using the request parameters. 3. Validate that the download belongs to the requesting user. 4. Call `DownloadAssembler.canBlocklist(download, false)` to verify if they are authorized to blocklist it. 5. Proceed with the blocklist and search command if authorized; otherwise, return a `403 Forbidden` error.
Gandalf added the Kind/Bug label 2026-05-22 19:16:27 +01:00
Author
Owner

Fixed the overly restrictive admin check in the blocklist-search endpoint. Non-admin users can now use the blocklist feature when they meet qualifying conditions (import issues or stale low-availability torrents). Changes:

  • DownloadMatcher.js: Exposed arrQueueId, arrType, arrInstanceUrl, arrContentId, arrContentType to non-admins while keeping sensitive fields (arrInstanceKey, arrLink, downloadPath, targetPath) admin-only
  • dashboard.js: Replaced blanket admin check with canBlocklist() validation and server-side API key lookup
  • dashboard.test.js: Updated tests to reflect new permission model

All integration tests pass.

Fixed the overly restrictive admin check in the blocklist-search endpoint. Non-admin users can now use the blocklist feature when they meet qualifying conditions (import issues or stale low-availability torrents). Changes: - DownloadMatcher.js: Exposed arrQueueId, arrType, arrInstanceUrl, arrContentId, arrContentType to non-admins while keeping sensitive fields (arrInstanceKey, arrLink, downloadPath, targetPath) admin-only - dashboard.js: Replaced blanket admin check with canBlocklist() validation and server-side API key lookup - dashboard.test.js: Updated tests to reflect new permission model All integration tests pass.
Gandalf added the Area/Frontend label 2026-05-28 11:53:58 +01:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Gandalf/sofarr#34