const assert = require('node:assert/strict'); const test = require('node:test'); const jwt = require('jsonwebtoken'); const { DesktopSessionError, buildDesktopCapabilities, createDesktopSession, createSsoTicket, exchangeSsoTicket, normalizeRedirectPath, resetDesktopSessionStateForTests, revokeDesktopSession, } = require('../src/services/desktopSessionService'); const CLIENT_ID = '11111111-1111-4111-8111-111111111111'; const ORIGINAL_SECRET = process.env.CUBEJS_SECRET; process.env.CUBEJS_SECRET = process.env.CUBEJS_SECRET || 'desktop-session-test-secret'; function createFakeCache() { const values = new Map(); return { values, async get(key) { return values.get(key) ?? null; }, async setex(key, _ttl, value) { values.set(key, value); return true; }, async take(key) { const value = values.get(key) ?? null; values.delete(key); return value; }, }; } function resolvedUser(overrides = {}) { return { id: 7, username: 'operator', name: '运营人员', email: 'operator@example.com', role: 'user', status: 'active', auth_source: 'dingtalk', departmentName: '运营中心', allowedPageKeys: ['planning_upload', 'market_insight'], ...overrides, }; } async function issueDesktopSession(options = {}) { return createDesktopSession({ userId: 7, payload: { clientId: CLIENT_ID, clientVersion: '0.0.10', platform: 'darwin', architecture: 'arm64', }, }, { resolveUser: async () => resolvedUser(options.user), }); } test.afterEach(() => resetDesktopSessionStateForTests()); test.after(() => { if (ORIGINAL_SECRET === undefined) delete process.env.CUBEJS_SECRET; else process.env.CUBEJS_SECRET = ORIGINAL_SECRET; }); test('desktop session is device-bound and returns server capabilities', async () => { const result = await issueDesktopSession(); const claims = jwt.verify(result.desktopSessionToken, process.env.CUBEJS_SECRET); assert.equal(claims.tokenType, 'desktop-session'); assert.equal(claims.clientId, CLIENT_ID); assert.equal(result.bootstrap.user.name, '运营人员'); assert.equal(result.bootstrap.capabilities.controlCenter, true); assert.equal(result.bootstrap.capabilities.autoListing, true); }); test('desktop capabilities follow resolved page permissions', () => { assert.deepEqual(buildDesktopCapabilities(resolvedUser({ allowedPageKeys: [] })), { controlCenter: true, autoListing: false, presale: false, pricing: false, alibaba1688: false, shopManagement: false, execution: false, logs: true, marketingEvents: false, promotion: false, productTest: false, }); assert.equal(buildDesktopCapabilities(resolvedUser({ role: 'admin', allowedPageKeys: [] })).promotion, true); }); test('SSO ticket is consumed exactly once and produces a normal web token', async () => { const cache = createFakeCache(); const desktop = await issueDesktopSession(); const claims = jwt.verify(desktop.desktopSessionToken, process.env.CUBEJS_SECRET); const ticket = await createSsoTicket({ claims, clientId: CLIENT_ID, redirectPath: '/planning/market-replica?source=app', }, { cache }); const exchanged = await exchangeSsoTicket(ticket.ticket, { cache, resolveUser: async () => resolvedUser(), }); const webClaims = jwt.verify(exchanged.accessToken, process.env.CUBEJS_SECRET); assert.equal(webClaims.sub, 7); assert.equal(webClaims.tokenType, undefined); assert.equal(exchanged.redirectPath, '/planning/market-replica?source=app&embed=desktop'); await assert.rejects( exchangeSsoTicket(ticket.ticket, { cache, resolveUser: async () => resolvedUser() }), (error) => error instanceof DesktopSessionError && error.code === 'DESKTOP_SSO_TICKET_INVALID' ); }); test('revoked desktop session cannot mint or exchange SSO tickets', async () => { const cache = createFakeCache(); const desktop = await issueDesktopSession(); const claims = jwt.verify(desktop.desktopSessionToken, process.env.CUBEJS_SECRET); const ticket = await createSsoTicket({ claims, clientId: CLIENT_ID }, { cache }); await revokeDesktopSession(claims, { cache }); await assert.rejects( createSsoTicket({ claims, clientId: CLIENT_ID }, { cache }), (error) => error.code === 'DESKTOP_SESSION_REVOKED' ); await assert.rejects( exchangeSsoTicket(ticket.ticket, { cache, resolveUser: async () => resolvedUser() }), (error) => error.code === 'DESKTOP_SESSION_REVOKED' ); }); test('desktop redirects are limited to control-center paths and always mark embed mode', () => { assert.equal(normalizeRedirectPath('https://evil.example/path'), '/dashboard?embed=desktop'); assert.equal(normalizeRedirectPath('//evil.example/path'), '/dashboard?embed=desktop'); assert.equal(normalizeRedirectPath('/login'), '/dashboard?embed=desktop'); assert.equal(normalizeRedirectPath('/settings/users?tab=active'), '/settings/users?tab=active&embed=desktop'); });