Import source: backend/src/routes/links

Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
This commit is contained in:
arsam
2026-09-18 23:13:27 +03:30
parent 2a23294ac9
commit 305f5b3804
+89
View File
@@ -0,0 +1,89 @@
import express from 'express';
import { HttpError } from '../middleware/errorHandler.js';
import { store } from '../services/store.js';
import { fileToApi } from '../utils/files.js';
import { getPreviewKind, getPreviewMeta } from '../utils/preview.js';
import * as gdrive from '../utils/gdrive.js';
import { recordEventInDb } from '../services/analytics.js';
import { rateLimit } from '../middleware/rateLimit.js';
const router = express.Router();
function isExpired(expiresAt: string) {
return new Date(expiresAt).getTime() <= Date.now();
}
router.get('/:linkId', async (req, res) => {
const ip = req.ip;
const userAgent = req.headers['user-agent'] as string;
const referrer = (req.headers.referer || req.headers.referrer) as string;
const file = await store.update((db) => {
const row = db.files.find((f) => f.linkId === req.params.linkId && f.status === 'uploaded');
if (!row) return null;
if (isExpired(row.expiresAt)) {
row.status = 'expired';
row.deletedAt = new Date().toISOString();
return null;
}
recordEventInDb(db, row.linkId, 'view', ip, userAgent, referrer);
return row;
});
if (!file) throw new HttpError(404, 'LINK_NOT_FOUND', 'Shared file not found or expired');
res.json({ data: fileToApi(file) });
});
// Limit downloads and previews to 60 per minute per IP to prevent egress flooding
const downloadLimiter = rateLimit(60, 60000);
/** Increment download counter then redirect to Google Drive's direct download URL. */
router.get('/:linkId/download', downloadLimiter, async (req, res) => {
const ip = req.ip;
const userAgent = req.headers['user-agent'] as string;
const referrer = (req.headers.referer || req.headers.referrer) as string;
const file = await store.update((db) => {
const row = db.files.find((f) => f.linkId === req.params.linkId && f.status === 'uploaded');
if (!row || isExpired(row.expiresAt)) return null;
recordEventInDb(db, row.linkId, 'download', ip, userAgent, referrer);
return row;
});
if (!file) throw new HttpError(404, 'LINK_NOT_FOUND', 'Shared file not found or expired');
res.redirect(302, gdrive.downloadUrl(file.gdriveId));
});
/**
* Stream preview content directly from Drive via rclone cat — no disk writes.
* Only available for supported types under the preview size limit.
* The browser follows this as a normal src= URL (img, video, audio, iframe, fetch).
*/
router.get('/:linkId/preview', downloadLimiter, async (req, res) => {
const db = await store.read();
const file = db.files.find((f) => f.linkId === req.params.linkId && f.status === 'uploaded');
if (!file || isExpired(file.expiresAt)) {
throw new HttpError(404, 'LINK_NOT_FOUND', 'Shared file not found or expired');
}
const preview = getPreviewMeta(file);
const kind = getPreviewKind(file.mimeType);
if (!preview.available || !kind) {
throw new HttpError(413, 'PREVIEW_NOT_AVAILABLE', 'Preview is not available for this file');
}
const contentType = kind === 'text' ? 'text/plain; charset=utf-8' : file.mimeType;
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('Content-Type', contentType);
res.setHeader('Content-Disposition', `inline; filename="${encodeURIComponent(file.originalName)}"`);
res.setHeader('Content-Security-Policy', "default-src 'none'; style-src 'unsafe-inline'");
const fileStream = await gdrive.getStream(file.gdriveId);
fileStream.pipe(res);
fileStream.on('error', () => {
if (!res.headersSent) res.status(502).json({ error: 'STREAM_ERROR', message: 'Could not stream file from storage' });
});
});
export { router as linksRouter };