const express = require('express'); const crypto = require('crypto'); const authMiddleware = require('../middleware/auth'); const { DesktopSessionError, createDesktopSession, createSsoTicket, exchangeSsoTicket, getDesktopBootstrap, revokeDesktopSession, } = require('../services/desktopSessionService'); const router = express.Router(); function requestUserId(req) { return req.user?.sub ?? req.user?.id; } function sendDesktopSessionError(res, error, fallbackMessage) { if (error instanceof DesktopSessionError) { return res.status(error.status).json({ success: false, error: error.message, code: error.code, }); } console.error(fallbackMessage, error); return res.status(500).json({ success: false, error: fallbackMessage }); } function safeScriptJson(value) { return JSON.stringify(value) .replace(//g, '\\u003e') .replace(/&/g, '\\u0026') .replace(/\u2028/g, '\\u2028') .replace(/\u2029/g, '\\u2029'); } function sendSsoExchangeHtml(res, result) { const nonce = crypto.randomBytes(18).toString('base64'); res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, private'); res.setHeader('Pragma', 'no-cache'); res.setHeader('Referrer-Policy', 'no-referrer'); res.setHeader('X-Content-Type-Options', 'nosniff'); res.setHeader( 'Content-Security-Policy', `default-src 'none'; script-src 'nonce-${nonce}'; style-src 'nonce-${nonce}'; base-uri 'none'; form-action 'none'; frame-ancestors 'self'` ); res.type('html').send(` 正在进入总控 正在进入总控... `); } router.post('/session', authMiddleware, async (req, res) => { try { if (req.user?.tokenType) { throw new DesktopSessionError('请使用用户登录令牌创建桌面会话', 401, 'DESKTOP_USER_TOKEN_REQUIRED'); } const data = await createDesktopSession({ userId: requestUserId(req), payload: req.body || {}, }); res.setHeader('Cache-Control', 'no-store'); return res.json({ success: true, data }); } catch (error) { return sendDesktopSessionError(res, error, '创建桌面会话失败'); } }); router.get('/bootstrap', authMiddleware, async (req, res) => { try { const data = await getDesktopBootstrap({ claims: req.user, clientId: req.query.clientId, }); res.setHeader('Cache-Control', 'no-store'); return res.json({ success: true, data }); } catch (error) { return sendDesktopSessionError(res, error, '读取桌面启动配置失败'); } }); router.post('/sso-ticket', authMiddleware, async (req, res) => { try { const data = await createSsoTicket({ claims: req.user, clientId: req.body?.clientId, redirectPath: req.body?.redirectPath, }); res.setHeader('Cache-Control', 'no-store'); return res.json({ success: true, data }); } catch (error) { return sendDesktopSessionError(res, error, '创建总控登录票据失败'); } }); router.get('/sso/exchange', async (req, res) => { try { const result = await exchangeSsoTicket(req.query.ticket); return sendSsoExchangeHtml(res, result); } catch (error) { if (error instanceof DesktopSessionError) { res.setHeader('Cache-Control', 'no-store'); return res.status(error.status).type('html').send('登录失效登录票据无效或已过期,请返回桌面客户端重试。'); } console.error('交换总控登录票据失败', error); return res.status(500).type('html').send('登录失败总控登录失败,请稍后重试。'); } }); router.post('/session/revoke', authMiddleware, async (req, res) => { try { const data = await revokeDesktopSession(req.user); res.setHeader('Cache-Control', 'no-store'); return res.json({ success: true, data }); } catch (error) { return sendDesktopSessionError(res, error, '退出桌面会话失败'); } }); module.exports = router;