Address PR review: dedicated download secret, shared constants, strip filePath, streaming zip

- jwt.ts: Use JWT_DOWNLOAD_SECRET instead of JWT_SECRET for download tokens
- audio-formats.ts: Add EBOOK_EXTENSIONS export alongside AUDIO_EXTENSIONS
- request-statuses.ts: New shared COMPLETED_STATUSES constant used across requests API, download route, and RequestCard
- requests/route.ts: Import COMPLETED_STATUSES; strip filePath from audiobook in API response
- download/route.ts: Import format/status constants; add archiver dependency and replace adm-zip with streaming archiver for multi-file zips
- RequestCard.tsx: Use shared COMPLETED_STATUSES constant
This commit is contained in:
razzamatazm
2026-02-26 16:20:37 -08:00
parent 1006a04337
commit e1629ce516
9 changed files with 880 additions and 56 deletions
+13
View File
@@ -67,3 +67,16 @@ export type TorrentTitleFormat = (typeof TORRENT_TITLE_FORMATS)[number];
* 'OTHER' is used when no recognized format is detected in the title.
*/
export type AudioFormat = TorrentTitleFormat | 'OTHER';
/**
* All supported ebook file extensions for ebook detection and file serving.
*/
export const EBOOK_EXTENSIONS = [
'.epub',
'.pdf',
'.mobi',
'.azw3',
'.fb2',
'.cbz',
'.cbr',
] as const;
+7
View File
@@ -0,0 +1,7 @@
/**
* Component: Request Status Constants
* Documentation: documentation/backend/database.md
*/
/** Terminal statuses indicating a request has been fulfilled and files are ready */
export const COMPLETED_STATUSES = ['available', 'downloaded'] as const;
+3 -2
View File
@@ -10,6 +10,7 @@ const logger = RMABLogger.create('JWT');
const JWT_SECRET = process.env.JWT_SECRET || 'change-this-to-a-random-secret-key';
const JWT_REFRESH_SECRET = process.env.JWT_REFRESH_SECRET || 'change-this-to-another-random-secret-key';
const JWT_DOWNLOAD_SECRET = process.env.JWT_DOWNLOAD_SECRET || JWT_SECRET + '-download';
const ACCESS_TOKEN_EXPIRY = '1h'; // 1 hour
const REFRESH_TOKEN_EXPIRY = '7d'; // 7 days
@@ -91,7 +92,7 @@ export interface DownloadTokenPayload {
*/
export function generateDownloadToken(userId: string, requestId: string): string {
const payload: DownloadTokenPayload = { sub: userId, requestId, type: 'download' };
return jwt.sign(payload, JWT_SECRET, { expiresIn: DOWNLOAD_TOKEN_EXPIRY });
return jwt.sign(payload, JWT_DOWNLOAD_SECRET, { expiresIn: DOWNLOAD_TOKEN_EXPIRY });
}
/**
@@ -99,7 +100,7 @@ export function generateDownloadToken(userId: string, requestId: string): string
*/
export function verifyDownloadToken(token: string): DownloadTokenPayload | null {
try {
const decoded = jwt.verify(token, JWT_SECRET) as DownloadTokenPayload;
const decoded = jwt.verify(token, JWT_DOWNLOAD_SECRET) as DownloadTokenPayload;
if (decoded.type !== 'download') return null;
return decoded;
} catch {