mirror of
https://github.com/nimbold/Firelink.git
synced 2026-09-03 14:37:56 +00:00
fix(torrent): harden allocation and credential isolation
- Extend allocation-phase eligibility to preallocated Torrent admission while excluding none, verify-only, and media work. - Strip Torrent metadata credentials at intake, persistence, renderer, native, and Aria2 header boundaries. - Add restart, batch-admission, persistence, and native regression coverage.
This commit is contained in:
@@ -9,6 +9,7 @@ import {
|
||||
categoryForDownload,
|
||||
categoryForFileName,
|
||||
isAllocationPhaseVisible,
|
||||
isAllocationPhaseEligible,
|
||||
isValidTorrentExcludeTrackerList,
|
||||
isValidTorrentTrackerList,
|
||||
normalizeTorrentEncryptionPolicy,
|
||||
@@ -88,6 +89,24 @@ describe('download persistence progress snapshots', () => {
|
||||
expect(persisted.headers).toBeUndefined();
|
||||
});
|
||||
|
||||
it('does not create a credential gate for Torrent metadata context', () => {
|
||||
const persisted = redactDownloadForPersistence({
|
||||
...item('paused'),
|
||||
isTorrent: true,
|
||||
username: 'browser-user',
|
||||
password: 'secret',
|
||||
cookies: 'session=metadata-only',
|
||||
headers: 'User-Agent: browser',
|
||||
credentialsRequired: true,
|
||||
});
|
||||
|
||||
expect(persisted.credentialsRequired).toBeUndefined();
|
||||
expect(persisted.username).toBeUndefined();
|
||||
expect(persisted.password).toBeUndefined();
|
||||
expect(persisted.cookies).toBeUndefined();
|
||||
expect(persisted.headers).toBeUndefined();
|
||||
});
|
||||
|
||||
it.each(['queued', 'staged', 'retrying', 'processing'] as const)(
|
||||
'keeps byte counters for %s snapshots',
|
||||
(status) => {
|
||||
@@ -116,6 +135,15 @@ describe('allocation phase visibility', () => {
|
||||
expect(isAllocationPhaseVisible(true, 'completed')).toBe(false);
|
||||
expect(isAllocationPhaseVisible(false, 'downloading')).toBe(false);
|
||||
});
|
||||
|
||||
it('uses Torrent allocation settings and excludes media and verify-only work', () => {
|
||||
expect(isAllocationPhaseEligible({ isTorrent: true, torrentFileAllocation: undefined })).toBe(true);
|
||||
expect(isAllocationPhaseEligible({ isTorrent: true, torrentFileAllocation: 'prealloc' })).toBe(true);
|
||||
expect(isAllocationPhaseEligible({ isTorrent: true, torrentFileAllocation: 'none' })).toBe(false);
|
||||
expect(isAllocationPhaseEligible({ isTorrent: true, torrentVerifyOnly: true })).toBe(false);
|
||||
expect(isAllocationPhaseEligible({ isTorrent: true, isMedia: true })).toBe(false);
|
||||
expect(isAllocationPhaseEligible({ isTorrent: false, isMedia: false })).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Torrent tracker input validation', () => {
|
||||
|
||||
+21
-1
@@ -55,6 +55,20 @@ export const isAllocationPhaseVisible = (
|
||||
status: DownloadStatus,
|
||||
): boolean => allocationPending && status !== 'completed' && status !== 'paused';
|
||||
|
||||
/**
|
||||
* Allocation is a transient admission phase. Normal downloads retain the
|
||||
* existing preallocation behavior; Torrent rows use Aria2's Torrent-specific
|
||||
* allocation setting and never show the hint for verification-only work.
|
||||
*/
|
||||
export const isAllocationPhaseEligible = (
|
||||
download: Pick<DownloadItem, 'isMedia' | 'isTorrent' | 'torrentFileAllocation' | 'torrentVerifyOnly'>,
|
||||
): boolean => {
|
||||
if (download.isMedia === true) return false;
|
||||
if (download.isTorrent !== true) return true;
|
||||
return download.torrentVerifyOnly !== true
|
||||
&& normalizeTorrentFileAllocation(download.torrentFileAllocation) !== 'none';
|
||||
};
|
||||
|
||||
export const DOWNLOAD_CONNECTIONS_MIN = 1;
|
||||
export const DOWNLOAD_CONNECTIONS_MAX = 16;
|
||||
|
||||
@@ -590,7 +604,13 @@ const VOLATILE_PROGRESS_STATUSES = new Set([
|
||||
*/
|
||||
export const redactDownloadForPersistence = (item: DownloadItem): DownloadItem => {
|
||||
const copy: DownloadItem = { ...item };
|
||||
if (item.credentialsRequired === true
|
||||
if (item.isTorrent === true) {
|
||||
// Torrent request credentials belong only to metadata acquisition. A
|
||||
// legacy row may still carry the marker or username in memory, but neither
|
||||
// may turn a cached-metadata Torrent into a credential-gated restart.
|
||||
delete copy.credentialsRequired;
|
||||
delete copy.username;
|
||||
} else if (item.credentialsRequired === true
|
||||
|| DOWNLOAD_SECRET_FIELDS.some(field => Boolean(item[field]))) {
|
||||
copy.credentialsRequired = true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user