Add sourceHeaders and conditional OIDC groups

Add support for passing sourceHeaders when fetching NZB/torrent files: extend AddDownloadOptions and SABnzbd AddNZBOptions, forward headers in sabnzbd and nzbget clients, and populate sourceHeaders in download-torrent.processor (injecting Prowlarr API key as X-Api-Key for proxy URLs). Make OIDC request scope conditional: only include the 'groups' scope when group-based access control or admin-claim is enabled (update provider logic, add tests, and update setup UI text). Also remove explicit take:100 in Plex processors and add CLAUDE guidance about requesting approval before implementing code changes.
This commit is contained in:
kikootwo
2026-03-09 10:33:52 -04:00
parent 9cb9d06144
commit 789a2e50ef
10 changed files with 92 additions and 4 deletions
+1 -1
View File
@@ -272,7 +272,7 @@ export function OIDCConfigStep({
<ul className="text-sm text-blue-700 dark:text-blue-300 mt-1 space-y-1">
<li> The redirect URI will be: {typeof window !== 'undefined' ? `${window.location.origin}/api/auth/oidc/callback` : '[Your Domain]/api/auth/oidc/callback'}</li>
<li> Configure this redirect URI in your OIDC provider settings</li>
<li> Required scopes: openid, profile, email, groups</li>
<li> Required scopes: openid, profile, email (groups is added automatically when group-based access control is enabled)</li>
</ul>
</div>
</div>
+1
View File
@@ -226,6 +226,7 @@ export class NZBGetService implements IDownloadClient {
responseType: 'arraybuffer',
timeout: 30000,
maxRedirects: 5,
headers: options?.sourceHeaders,
httpsAgent: url.startsWith('https') ? this.httpsAgent : undefined,
});
+4
View File
@@ -24,6 +24,8 @@ export interface AddNZBOptions {
category?: string;
priority?: 'low' | 'normal' | 'high' | 'force';
paused?: boolean;
/** Headers to include when fetching the NZB from the source URL */
sourceHeaders?: Record<string, string>;
}
export interface NZBInfo {
@@ -492,6 +494,7 @@ export class SABnzbdService implements IDownloadClient {
responseType: 'arraybuffer',
timeout: 30000,
maxRedirects: 5,
headers: options?.sourceHeaders,
// Use the same SSL settings as the SABnzbd client if the NZB URL
// happens to be served over HTTPS with a self-signed cert
httpsAgent: url.startsWith('https') ? this.httpsAgent : undefined,
@@ -787,6 +790,7 @@ export class SABnzbdService implements IDownloadClient {
category: options?.category,
priority: options?.priority ? priorityMap[options.priority] || 'normal' : undefined,
paused: options?.paused,
sourceHeaders: options?.sourceHeaders,
});
}
@@ -102,6 +102,8 @@ export interface AddDownloadOptions {
priority?: string;
/** Whether to add in paused state */
paused?: boolean;
/** Headers to include when fetching the source file (e.g. Prowlarr API key for proxy URLs) */
sourceHeaders?: Record<string, string>;
}
/** Result of a connection test */
@@ -58,10 +58,19 @@ export async function processDownloadTorrent(payload: DownloadTorrentPayload): P
logger.info(`Routing to ${client.clientType} (${client.protocol})`);
// Include Prowlarr API key as source header so NZB/torrent downloads from
// Prowlarr proxy URLs are authenticated (fixes 403 for indexers like NZBFinder)
const prowlarrApiKey = (await config.getMany(['prowlarr_api_key'])).prowlarr_api_key || process.env.PROWLARR_API_KEY;
const sourceHeaders: Record<string, string> = {};
if (prowlarrApiKey) {
sourceHeaders['X-Api-Key'] = prowlarrApiKey;
}
// Add download via unified interface
const downloadClientId = await client.addDownload(torrent.downloadUrl, {
category,
priority: 'normal',
sourceHeaders,
});
logger.info(`Download added with ID: ${downloadClientId}`);
@@ -265,7 +265,7 @@ export async function processPlexRecentlyAddedCheck(payload: PlexRecentlyAddedPa
},
},
},
take: 100,
});
if (matchableRequests.length > 0) {
+1 -1
View File
@@ -450,7 +450,7 @@ export async function processScanPlex(payload: ScanPlexPayload): Promise<any> {
},
},
},
take: 100, // Increased from 50 to handle more eligible requests
});
logger.info(`Found ${matchableRequests.length} matchable requests (all non-terminal statuses)`);
+7 -1
View File
@@ -98,9 +98,15 @@ export class OIDCAuthProvider implements IAuthProvider {
timestamp: Date.now(),
});
// Only request 'groups' scope when group-based features are configured
const accessMethod = await this.configService.get('oidc.access_control_method');
const adminClaimEnabled = await this.configService.get('oidc.admin_claim_enabled');
const needsGroups = accessMethod === 'group_claim' || adminClaimEnabled === 'true';
const scope = needsGroups ? 'openid profile email groups' : 'openid profile email';
// Generate authorization URL
const redirectUrl = client.authorizationUrl({
scope: 'openid profile email groups',
scope,
state,
nonce,
code_challenge: codeChallenge,