gongxiangp2/app/api/proxy-media/route.test.ts

86 lines
2.4 KiB
TypeScript

/** @jest-environment node */
import { lookup } from 'node:dns/promises'
import { NextRequest } from 'next/server'
import { GET } from './route'
jest.mock('node:dns/promises', () => ({
lookup: jest.fn(),
}))
jest.mock('@/lib/video-preview-access', () => ({
findBlockedVideoPreviewByUrl: jest.fn(),
isVideoMediaPath: jest.fn(() => false),
}))
const mockedLookup = lookup as jest.MockedFunction<typeof lookup>
function createRequest(targetUrl: string) {
return new NextRequest(
`https://sc.jiansun.vip/api/proxy-media?url=${encodeURIComponent(targetUrl)}`,
)
}
describe('/api/proxy-media', () => {
beforeEach(() => {
jest.clearAllMocks()
mockedLookup.mockResolvedValue([
{ address: '1.1.1.1', family: 4 },
] as any)
global.fetch = jest.fn() as jest.Mock
})
test('回环地址在发起网络请求前就被拒绝', async () => {
const response = await GET(createRequest('http://127.0.0.1:9000/a.jpg'))
expect(response.status).toBe(403)
expect(global.fetch).not.toHaveBeenCalled()
})
test('域名解析到内网地址时拒绝回源', async () => {
mockedLookup.mockResolvedValue([
{ address: '192.168.58.20', family: 4 },
] as any)
const response = await GET(createRequest('https://s3.1080p.hk/a.jpg'))
expect(response.status).toBe(403)
expect(global.fetch).not.toHaveBeenCalled()
})
test('公网 S3 使用手动跳转和流式响应', async () => {
;(global.fetch as jest.Mock).mockResolvedValue(new Response('image-data', {
status: 200,
headers: {
'content-type': 'image/jpeg',
'content-length': '10',
},
}))
const response = await GET(createRequest('https://s3.1080p.hk/a.jpg?token=secret'))
expect(response.status).toBe(200)
expect(await response.text()).toBe('image-data')
expect(global.fetch).toHaveBeenCalledWith(
'https://s3.1080p.hk/a.jpg?token=secret',
expect.objectContaining({
method: 'GET',
redirect: 'manual',
signal: expect.any(AbortSignal),
}),
)
})
test('每次上游跳转都会重新验证目标', async () => {
;(global.fetch as jest.Mock).mockResolvedValue(new Response(null, {
status: 302,
headers: { location: 'http://169.254.169.254/latest/meta-data' },
}))
const response = await GET(createRequest('https://s3.1080p.hk/a.jpg'))
expect(response.status).toBe(403)
expect(global.fetch).toHaveBeenCalledTimes(1)
})
})