139 lines
3.8 KiB
TypeScript
139 lines
3.8 KiB
TypeScript
import { NextRequest } from 'next/server'
|
|
|
|
jest.mock('@/lib/auth', () => ({
|
|
authOptions: {},
|
|
}))
|
|
|
|
jest.mock('next-auth', () => ({
|
|
getServerSession: jest.fn(),
|
|
}))
|
|
|
|
jest.mock('@/lib/config', () => ({
|
|
featureFlags: {
|
|
tunnelEnabled: false,
|
|
},
|
|
}))
|
|
|
|
jest.mock('@/lib/license', () => ({
|
|
canUseIntranetPenetration: jest.fn(),
|
|
}))
|
|
|
|
jest.mock('@/lib/prisma', () => ({
|
|
prisma: {
|
|
user: {
|
|
findUnique: jest.fn(),
|
|
},
|
|
systemSettings: {
|
|
findFirst: jest.fn(),
|
|
},
|
|
},
|
|
}))
|
|
|
|
jest.mock('@/lib/admin-permissions', () => ({
|
|
isCurrentSuperAdmin: jest.fn(),
|
|
}))
|
|
|
|
import { POST as startTunnel } from '../start/route'
|
|
import { GET as getTunnelStatus } from '../status/route'
|
|
import { POST as stopTunnel } from '../stop/route'
|
|
|
|
const { getServerSession } = require('next-auth')
|
|
const { canUseIntranetPenetration } = require('@/lib/license')
|
|
const { prisma } = require('@/lib/prisma')
|
|
const { isCurrentSuperAdmin } = require('@/lib/admin-permissions')
|
|
|
|
function buildRequest(method: string) {
|
|
return new NextRequest('http://localhost:3000/api/tunnel', { method })
|
|
}
|
|
|
|
describe('内网穿透 API 许可证边界', () => {
|
|
beforeEach(() => {
|
|
jest.resetAllMocks()
|
|
|
|
getServerSession.mockResolvedValue({
|
|
user: {
|
|
id: 'super-admin-1',
|
|
role: 'ADMIN',
|
|
isSuperAdmin: true,
|
|
},
|
|
})
|
|
|
|
prisma.systemSettings.findFirst.mockResolvedValue({
|
|
enableTunnelService: true,
|
|
})
|
|
|
|
isCurrentSuperAdmin.mockResolvedValue(true)
|
|
canUseIntranetPenetration.mockResolvedValue(true)
|
|
})
|
|
|
|
test('未登录不能启动内网穿透', async () => {
|
|
getServerSession.mockResolvedValue(null)
|
|
|
|
const response = await startTunnel(buildRequest('POST'))
|
|
const data = await response.json()
|
|
|
|
expect(response.status).toBe(401)
|
|
expect(data.error).toBe('未登录')
|
|
expect(canUseIntranetPenetration).not.toHaveBeenCalled()
|
|
})
|
|
|
|
test('旧会话带最高权限标记但数据库已撤销时不能启动', async () => {
|
|
getServerSession.mockResolvedValue({
|
|
user: {
|
|
id: 'admin-1',
|
|
role: 'ADMIN',
|
|
isSuperAdmin: true,
|
|
},
|
|
})
|
|
isCurrentSuperAdmin.mockResolvedValue(false)
|
|
|
|
const response = await startTunnel(buildRequest('POST'))
|
|
const data = await response.json()
|
|
|
|
expect(response.status).toBe(403)
|
|
expect(data.error).toContain('最高权限')
|
|
expect(prisma.systemSettings.findFirst).not.toHaveBeenCalled()
|
|
expect(canUseIntranetPenetration).not.toHaveBeenCalled()
|
|
})
|
|
|
|
test('许可证不包含内网穿透时不能启动', async () => {
|
|
canUseIntranetPenetration.mockResolvedValue(false)
|
|
|
|
const response = await startTunnel(buildRequest('POST'))
|
|
const data = await response.json()
|
|
|
|
expect(response.status).toBe(403)
|
|
expect(data.error).toContain('许可证')
|
|
})
|
|
|
|
test('许可证不包含内网穿透时不能查看状态', async () => {
|
|
canUseIntranetPenetration.mockResolvedValue(false)
|
|
|
|
const response = await getTunnelStatus(buildRequest('GET'))
|
|
const data = await response.json()
|
|
|
|
expect(response.status).toBe(403)
|
|
expect(data.status).toBe('license_restricted')
|
|
expect(data.error).toContain('许可证')
|
|
})
|
|
|
|
test('许可证不包含内网穿透时不能停止', async () => {
|
|
canUseIntranetPenetration.mockResolvedValue(false)
|
|
|
|
const response = await stopTunnel(buildRequest('POST'))
|
|
const data = await response.json()
|
|
|
|
expect(response.status).toBe(403)
|
|
expect(data.error).toContain('许可证')
|
|
})
|
|
|
|
test('最高权限账号且许可证允许时可以启动占位隧道', async () => {
|
|
const response = await startTunnel(buildRequest('POST'))
|
|
const data = await response.json()
|
|
|
|
expect(response.status).toBe(200)
|
|
expect(data.tunnelUrl).toBe('https://mock-tunnel.example.com')
|
|
expect(canUseIntranetPenetration).toHaveBeenCalled()
|
|
})
|
|
})
|