mirror of
https://github.com/nimbold/Firelink.git
synced 2026-09-02 22:17:56 +00:00
fix(add-window): harden intake admission and destination safety
- retain valid magnet clipboard handoffs and reject malformed magnet URLs - normalize destination identity and fail closed on deleted queues - redact malformed media headers and add focused regression coverage
This commit is contained in:
@@ -13,16 +13,23 @@ describe('clipboard URL extraction', () => {
|
||||
|
||||
it('reads only supported, unique download URLs from clipboard text', async () => {
|
||||
vi.mocked(readText).mockResolvedValue(
|
||||
'https://example.com/file.zip\nhttps://example.com/file.zip ftp://example.com/file.bin sftp://example.com/file.iso mailto:user@example.com'
|
||||
'https://example.com/file.zip\nhttps://example.com/file.zip ftp://example.com/file.bin sftp://example.com/file.iso magnet:?xt=urn:btih:0123456789abcdef0123456789abcdef01234567 mailto:user@example.com'
|
||||
);
|
||||
|
||||
await expect(readClipboardDownloadUrls()).resolves.toEqual([
|
||||
'https://example.com/file.zip',
|
||||
'ftp://example.com/file.bin',
|
||||
'sftp://example.com/file.iso',
|
||||
'magnet:?xt=urn:btih:0123456789abcdef0123456789abcdef01234567',
|
||||
]);
|
||||
});
|
||||
|
||||
it('ignores malformed magnet URLs at the clipboard boundary', async () => {
|
||||
vi.mocked(readText).mockResolvedValue('magnet: magnet:?invalid magnet://tracker/?xt=urn:btih:0123456789abcdef0123456789abcdef01234567');
|
||||
|
||||
await expect(readClipboardDownloadUrls()).resolves.toEqual([]);
|
||||
});
|
||||
|
||||
it('preserves clipboard read failures for the caller to handle', async () => {
|
||||
const error = new Error('clipboard unavailable');
|
||||
vi.mocked(readText).mockRejectedValue(error);
|
||||
|
||||
@@ -29,6 +29,12 @@ describe('download locations', () => {
|
||||
expect(downloadLocationEquals('/home/Test', 'Movie.MP4', '/home/test', 'movie.mp4', 'linux')).toBe(false);
|
||||
});
|
||||
|
||||
it('matches destinations with redundant separators without changing platform case rules', () => {
|
||||
expect(downloadLocationEquals('/Users/test//Downloads/', 'file.zip', '/Users/test/Downloads', 'file.zip', 'macos')).toBe(true);
|
||||
expect(downloadLocationEquals('//Users/test/Downloads', 'file.zip', '/Users/test/Downloads', 'file.zip', 'macos')).toBe(true);
|
||||
expect(downloadLocationEquals('\\\\server\\share\\downloads', 'file.zip', '//server//share/downloads/', 'file.zip', 'windows')).toBe(true);
|
||||
});
|
||||
|
||||
it('uses a remembered Add-window directory only when the setting is enabled', () => {
|
||||
expect(resolveInitialAddWindowLocation(
|
||||
'D:\\Downloads',
|
||||
|
||||
@@ -307,7 +307,14 @@ export const downloadLocationEquals = (
|
||||
os: string
|
||||
): boolean => {
|
||||
const normalize = (value: string) => {
|
||||
const normalized = value.replace(/\\/g, '/').replace(/\/+$/, '');
|
||||
const slashPath = value.replace(/\\/g, '/');
|
||||
// Collapse redundant separators without destroying a Windows UNC prefix.
|
||||
// Destination strings can come from legacy settings as well as the folder
|
||||
// picker, so lexical equality must not miss the same filesystem target.
|
||||
const leadingSeparators = slashPath.match(/^\/+/);
|
||||
const leadingCount = leadingSeparators ? leadingSeparators[0].length : 0;
|
||||
const prefix = os === 'windows' && leadingCount >= 2 ? '//' : leadingCount > 0 ? '/' : '';
|
||||
const normalized = `${prefix}${slashPath.slice(leadingCount).replace(/\/{2,}/g, '/')}`.replace(/\/+$/, '');
|
||||
return os === 'windows'
|
||||
? normalized.toLocaleLowerCase()
|
||||
: normalized;
|
||||
|
||||
+9
-1
@@ -11,7 +11,15 @@ export function extractValidDownloadUrls(text: string): string[] {
|
||||
for (const part of parts) {
|
||||
try {
|
||||
const url = new URL(part);
|
||||
if (url.protocol === 'http:' || url.protocol === 'https:' || url.protocol === 'ftp:' || url.protocol === 'sftp:') {
|
||||
const isValidMagnet = url.protocol !== 'magnet:' || (
|
||||
!url.username
|
||||
&& !url.password
|
||||
&& !url.hostname
|
||||
&& !url.port
|
||||
&& !url.hash
|
||||
&& url.searchParams.getAll('xt').some(value => /^urn:btih:(?:[0-9a-f]{40}|[a-z2-7]{32})$/i.test(value))
|
||||
);
|
||||
if ((url.protocol === 'http:' || url.protocol === 'https:' || url.protocol === 'ftp:' || url.protocol === 'sftp:' || url.protocol === 'magnet:') && isValidMagnet) {
|
||||
urls.push(url.toString());
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
Reference in New Issue
Block a user