From 1b03d3d180f4b12f5bd31d24d34bf93abc7e49cc Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Wed, 13 Jan 2021 18:55:23 +0800 Subject: [PATCH] server: handle case difference in ".torrent" download --- server/routes/api/torrents.ts | 13 ++++++++----- .../services/Transmission/clientGatewayService.ts | 4 ++-- .../services/interfaces/clientGatewayService.ts | 4 ++-- .../services/qBittorrent/clientGatewayService.ts | 10 +++++----- server/services/rTorrent/clientGatewayService.ts | 15 +++++++++++---- 5 files changed, 28 insertions(+), 18 deletions(-) diff --git a/server/routes/api/torrents.ts b/server/routes/api/torrents.ts index f9734e94..415ca559 100644 --- a/server/routes/api/torrents.ts +++ b/server/routes/api/torrents.ts @@ -569,15 +569,17 @@ router.get<{hashes: string}>( return; } - const sessionDirectory = await req.services?.clientGatewayService - ?.getClientSessionDirectory() - .catch(() => undefined); + const {path: sessionDirectory, case: torrentCase} = + (await req.services?.clientGatewayService?.getClientSessionDirectory().catch(() => undefined)) || {}; + if (sessionDirectory == null || !fs.existsSync(sessionDirectory)) { res.status(500).json(new Error('Failed to get session directory.')); return; } - const torrentFileNames = hashes.map((hash) => `${hash}.torrent`); + const torrentFileNames = hashes.map( + (hash) => `${torrentCase === 'lower' ? hash.toLowerCase() : hash.toUpperCase()}.torrent`, + ); if (hashes.length < 2) { res.attachment(torrentFileNames[0]); @@ -590,7 +592,8 @@ router.get<{hashes: string}>( fs.accessSync(path.join(sessionDirectory, torrentFileName), fs.constants.R_OK), ); } catch { - res.status(500).json('Failed to access torrent files.'); + res.status(404).json('Failed to access torrent files.'); + return; } res.attachment(`torrents-${Date.now()}.tar`); diff --git a/server/services/Transmission/clientGatewayService.ts b/server/services/Transmission/clientGatewayService.ts index 57a11a2d..87ed05a4 100644 --- a/server/services/Transmission/clientGatewayService.ts +++ b/server/services/Transmission/clientGatewayService.ts @@ -422,11 +422,11 @@ class TransmissionClientGatewayService extends ClientGatewayService { }); } - async getClientSessionDirectory(): Promise { + async getClientSessionDirectory(): Promise<{path: string; case: 'lower' | 'upper'}> { return this.clientRequestManager .getSessionProperties(['config-dir']) .then(this.processClientRequestSuccess, this.processClientRequestError) - .then((properties) => path.join(properties['config-dir'], 'torrents')); + .then((properties) => ({path: path.join(properties['config-dir'], 'torrents'), case: 'lower'})); } async getClientSettings(): Promise { diff --git a/server/services/interfaces/clientGatewayService.ts b/server/services/interfaces/clientGatewayService.ts index 60d5141e..918d82cc 100644 --- a/server/services/interfaces/clientGatewayService.ts +++ b/server/services/interfaces/clientGatewayService.ts @@ -183,9 +183,9 @@ abstract class ClientGatewayService extends BaseService} - Resolves with path of session directory or rejects with error. + * @return {Promise<{path: string; case: 'lower' | 'upper'}>} - Resolves with path of session directory or rejects with error. */ - abstract getClientSessionDirectory(): Promise; + abstract getClientSessionDirectory(): Promise<{path: string; case: 'lower' | 'upper'}>; /** * Gets settings of the torrent client diff --git a/server/services/qBittorrent/clientGatewayService.ts b/server/services/qBittorrent/clientGatewayService.ts index 9242d4db..620e34f7 100644 --- a/server/services/qBittorrent/clientGatewayService.ts +++ b/server/services/qBittorrent/clientGatewayService.ts @@ -386,19 +386,19 @@ class QBittorrentClientGatewayService extends ClientGatewayService { }); } - async getClientSessionDirectory(): Promise { + async getClientSessionDirectory(): Promise<{path: string; case: 'lower' | 'upper'}> { // qBittorrent API does not provide session directory. // We can only guess with the common locations here. switch (process.platform) { case 'win32': if (process.env.LOCALAPPDATA) { - return path.join(process.env.LOCALAPPDATA, '\\qBittorrent\\BT_backup'); + return {path: path.join(process.env.LOCALAPPDATA, '\\qBittorrent\\BT_backup'), case: 'lower'}; } - return path.join(homedir(), '\\AppData\\Local\\qBittorrent\\BT_backup'); + return {path: path.join(homedir(), '\\AppData\\Local\\qBittorrent\\BT_backup'), case: 'lower'}; case 'darwin': - return path.join(homedir(), '/Library/Application Support/qBittorrent/BT_backup'); + return {path: path.join(homedir(), '/Library/Application Support/qBittorrent/BT_backup'), case: 'lower'}; default: - return path.join(homedir(), '/.local/share/data/qBittorrent/BT_backup'); + return {path: path.join(homedir(), '/.local/share/data/qBittorrent/BT_backup'), case: 'lower'}; } } diff --git a/server/services/rTorrent/clientGatewayService.ts b/server/services/rTorrent/clientGatewayService.ts index fc4a2160..d6ea05b4 100644 --- a/server/services/rTorrent/clientGatewayService.ts +++ b/server/services/rTorrent/clientGatewayService.ts @@ -517,11 +517,17 @@ class RTorrentClientGatewayService extends ClientGatewayService { .methodCall('system.multicall', [methodCalls]) .then(this.processClientRequestSuccess, this.processClientRequestError); - const sessionDirectory = await this.getClientSessionDirectory(); + const {path: sessionDirectory, case: torrentCase} = await this.getClientSessionDirectory(); await Promise.all( [...new Set(hashes)].map(async (hash) => - setTrackers(path.join(sessionDirectory, sanitize(`${hash}.torrent`)), trackers), + setTrackers( + path.join( + sessionDirectory, + sanitize(`${torrentCase === 'lower' ? hash.toLowerCase() : hash.toUpperCase()}.torrent`), + ), + trackers, + ), ), ); } @@ -677,10 +683,11 @@ class RTorrentClientGatewayService extends ClientGatewayService { }); } - async getClientSessionDirectory(): Promise { + async getClientSessionDirectory(): Promise<{path: string; case: 'lower' | 'upper'}> { return this.clientRequestManager .methodCall('session.path', []) - .then(this.processClientRequestSuccess, this.processClientRequestError); + .then(this.processClientRequestSuccess, this.processClientRequestError) + .then((response) => ({path: response, case: 'upper'})); } async getClientSettings(): Promise {