fix(product-archive): allow trusted HTTPS image host on port 3333
This commit is contained in:
parent
e57f95c489
commit
b6a326d996
@ -71,6 +71,66 @@ describe('product archive source image service', () => {
|
||||
expect(fetchImpl).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
|
||||
it('allows the company HTTPS image host on port 3333', async () => {
|
||||
const imageUrl = 'https://static.jiansun.vip:3333/Resource/SkuImg/YMJ000904N754V01.jpg'
|
||||
const fetchImpl = jest.fn().mockResolvedValue(
|
||||
response({ contentType: 'image/jpeg' }),
|
||||
) as unknown as typeof fetch
|
||||
const service = new ProductArchiveSourceImageService(
|
||||
repository(imageUrl),
|
||||
fetchImpl,
|
||||
jest.fn().mockResolvedValue(['93.184.216.34']),
|
||||
)
|
||||
|
||||
await expect(service.readByBarcode('YMJ000904N722')).resolves.toEqual(
|
||||
expect.objectContaining({ contentType: 'image/jpeg' }),
|
||||
)
|
||||
expect(fetchImpl).toHaveBeenCalledWith(new URL(imageUrl), expect.anything())
|
||||
})
|
||||
|
||||
it.each([
|
||||
'https://images.example.com:3333/product.jpg',
|
||||
'https://static.jiansun.vip.example.com:3333/product.jpg',
|
||||
'https://static.jiansun.vip:8443/product.jpg',
|
||||
'http://static.jiansun.vip:3333/product.jpg',
|
||||
])('keeps untrusted image ports blocked: %s', async (imageUrl) => {
|
||||
const fetchImpl = jest.fn() as unknown as typeof fetch
|
||||
const service = new ProductArchiveSourceImageService(
|
||||
repository(imageUrl),
|
||||
fetchImpl,
|
||||
jest.fn().mockResolvedValue(['93.184.216.34']),
|
||||
)
|
||||
|
||||
await expect(service.readByBarcode('BARCODE-1')).rejects.toThrow('port is not allowed')
|
||||
expect(fetchImpl).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('keeps private addresses blocked for the trusted image host', async () => {
|
||||
const fetchImpl = jest.fn() as unknown as typeof fetch
|
||||
const service = new ProductArchiveSourceImageService(
|
||||
repository('https://static.jiansun.vip:3333/product.jpg'),
|
||||
fetchImpl,
|
||||
jest.fn().mockResolvedValue(['127.0.0.1']),
|
||||
)
|
||||
|
||||
await expect(service.readByBarcode('BARCODE-1')).rejects.toThrow('private address')
|
||||
expect(fetchImpl).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('validates redirects from the trusted host before following them', async () => {
|
||||
const fetchImpl = jest.fn().mockResolvedValue(
|
||||
response({ status: 302, location: 'https://images.example.com:3333/product.jpg' }),
|
||||
) as unknown as typeof fetch
|
||||
const service = new ProductArchiveSourceImageService(
|
||||
repository('https://static.jiansun.vip:3333/product.jpg'),
|
||||
fetchImpl,
|
||||
jest.fn().mockResolvedValue(['93.184.216.34']),
|
||||
)
|
||||
|
||||
await expect(service.readByBarcode('BARCODE-1')).rejects.toThrow('port is not allowed')
|
||||
expect(fetchImpl).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('blocks source URLs that resolve to a private address', async () => {
|
||||
const sourceRepository = repository('http://internal.example.com/product.jpg')
|
||||
const fetchImpl = jest.fn() as unknown as typeof fetch
|
||||
|
||||
@ -83,9 +83,15 @@ function isPrivateAddress(address: string) {
|
||||
async function assertPublicImageUrl(url: URL, resolveAddresses: ResolveAddresses) {
|
||||
if (!['http:', 'https:'].includes(url.protocol)) throw new Error('Unsupported image protocol')
|
||||
if (url.username || url.password) throw new Error('Image URL credentials are not allowed')
|
||||
if (url.port && !['80', '443'].includes(url.port)) throw new Error('Image URL port is not allowed')
|
||||
|
||||
const hostname = url.hostname.trim().toLowerCase()
|
||||
// JST SKU photos also use the company's HTTPS image host on port 3333.
|
||||
const isTrustedImagePort = url.protocol === 'https:'
|
||||
&& hostname === 'static.jiansun.vip'
|
||||
&& url.port === '3333'
|
||||
if (url.port && !['80', '443'].includes(url.port) && !isTrustedImagePort) {
|
||||
throw new Error('Image URL port is not allowed')
|
||||
}
|
||||
|
||||
if (!hostname || hostname === 'localhost' || hostname.endsWith('.local')) {
|
||||
throw new Error('Image URL hostname is not public')
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user