mirror of
https://github.com/UNITRONIX/BetterDesk.git
synced 2026-09-10 09:35:39 +00:00
dd0889e3d6
Introduce a SessionManager for relay-based remote sessions in the Tauri MGMT client: new SessionCommand API, start/stop/session input routing, clipboard/recording/quality controls, and notification read/dismiss state. Wire AppState with new mutexes and show main window on startup. CI: add SBOM generation (anchore) and Trivy vulnerability scan steps. Misc: change console Docker DB path, large README/CHANGELOG updates (chat E2E, unattended access/WOL, i18n expansion, CDAP/SDK docs), and many web-nodejs assets/locales/routes/views/services and server-side changes.
101 lines
3.2 KiB
JavaScript
101 lines
3.2 KiB
JavaScript
/**
|
|
* BetterDesk Console — Chat Routes
|
|
* Dedicated chat page + API endpoints for Chat 2.0
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
const express = require('express');
|
|
const router = express.Router();
|
|
const multer = require('multer');
|
|
const path = require('path');
|
|
const fs = require('fs');
|
|
const crypto = require('crypto');
|
|
const { requireAuth } = require('../middleware/auth');
|
|
|
|
// File upload config — max 50MB, store in data/chat-files/
|
|
const UPLOAD_DIR = path.join(__dirname, '..', 'data', 'chat-files');
|
|
const MAX_FILE_SIZE = 50 * 1024 * 1024; // 50MB
|
|
|
|
if (!fs.existsSync(UPLOAD_DIR)) {
|
|
fs.mkdirSync(UPLOAD_DIR, { recursive: true });
|
|
}
|
|
|
|
const upload = multer({
|
|
storage: multer.diskStorage({
|
|
destination: (_req, _file, cb) => cb(null, UPLOAD_DIR),
|
|
filename: (_req, file, cb) => {
|
|
const id = crypto.randomBytes(16).toString('hex');
|
|
const ext = path.extname(file.originalname).slice(0, 10);
|
|
cb(null, `${id}${ext}`);
|
|
},
|
|
}),
|
|
limits: { fileSize: MAX_FILE_SIZE },
|
|
});
|
|
|
|
// ========== Page Route ==========
|
|
|
|
router.get('/chat', requireAuth, (req, res) => {
|
|
res.render('chat', {
|
|
title: req.t('nav.chat'),
|
|
pageStyles: ['chat'],
|
|
pageScripts: ['chat'],
|
|
currentPage: 'chat',
|
|
breadcrumb: [{ label: req.t('nav.chat') }],
|
|
});
|
|
});
|
|
|
|
// ========== API Routes ==========
|
|
|
|
// Upload encrypted file
|
|
router.post('/api/chat/upload', requireAuth, upload.single('file'), (req, res) => {
|
|
if (!req.file) {
|
|
return res.status(400).json({ success: false, error: 'No file provided' });
|
|
}
|
|
const fileId = path.basename(req.file.filename, path.extname(req.file.filename));
|
|
res.json({
|
|
success: true,
|
|
file_id: fileId,
|
|
filename: req.file.filename,
|
|
size: req.file.size,
|
|
url: `/api/chat/files/${fileId}`,
|
|
});
|
|
});
|
|
|
|
// Download file
|
|
router.get('/api/chat/files/:fileId', requireAuth, (req, res) => {
|
|
const fileId = req.params.fileId.replace(/[^a-f0-9]/gi, '');
|
|
if (!fileId) return res.status(400).json({ success: false, error: 'Invalid file ID' });
|
|
|
|
// Find file by ID prefix
|
|
const files = fs.readdirSync(UPLOAD_DIR).filter(f => f.startsWith(fileId));
|
|
if (files.length === 0) {
|
|
return res.status(404).json({ success: false, error: 'File not found' });
|
|
}
|
|
const filePath = path.join(UPLOAD_DIR, files[0]);
|
|
// Verify path traversal protection
|
|
if (!filePath.startsWith(UPLOAD_DIR)) {
|
|
return res.status(403).json({ success: false, error: 'Forbidden' });
|
|
}
|
|
res.download(filePath);
|
|
});
|
|
|
|
// Search messages via Go server proxy
|
|
router.get('/api/chat/search', requireAuth, async (req, res) => {
|
|
try {
|
|
const { apiClient } = require('../services/betterdeskApi');
|
|
const query = String(req.query.q || '').slice(0, 200);
|
|
const conversationId = req.query.conversation_id || '';
|
|
if (!query) return res.json({ success: true, messages: [] });
|
|
|
|
const resp = await apiClient.get('/api/chat/search', {
|
|
params: { q: query, conversation_id: conversationId, limit: 50 },
|
|
});
|
|
res.json({ success: true, messages: resp.data?.messages || [] });
|
|
} catch (e) {
|
|
res.json({ success: true, messages: [] });
|
|
}
|
|
});
|
|
|
|
module.exports = router;
|