fix: hetzner returns invalid URLs as Location

This commit is contained in:
Robert Schäfer 2025-05-30 21:32:04 +08:00
parent d5ded75078
commit b37bdb6c80
3 changed files with 50 additions and 13 deletions

View File

@ -28,11 +28,11 @@ export const TEST_CONFIG: typeof CONFIG = {
REDIS_PORT: undefined,
REDIS_PASSWORD: undefined,
AWS_ACCESS_KEY_ID: '',
AWS_SECRET_ACCESS_KEY: '',
AWS_ENDPOINT: '',
AWS_REGION: '',
AWS_BUCKET: '',
AWS_ACCESS_KEY_ID: 'AWS_ACCESS_KEY_ID',
AWS_SECRET_ACCESS_KEY: 'AWS_SECRET_ACCESS_KEY',
AWS_ENDPOINT: 'AWS_ENDPOINT',
AWS_REGION: 'AWS_REGION',
AWS_BUCKET: 'AWS_BUCKET',
S3_PUBLIC_GATEWAY: undefined,
IMAGOR_SECRET: undefined,

View File

@ -0,0 +1,36 @@
import { TEST_CONFIG } from '@src/config/test-mock'
import ImageResolver from './images'
describe('Image', () => {
const { Image } = ImageResolver
const args = {}
const Location =
'fsn1.your-objectstorage.com/ocelot-social-staging/original/f965ea15-1f6b-43aa-a535-927410e2585e-dsc02586.jpg'
const config = {
...TEST_CONFIG,
AWS_ENDPOINT: 'https://fsn1.your-objectstorage.com',
S3_PUBLIC_GATEWAY: 'https://your-public-gateway.com',
IMAGOR_SECRET: 'IMAGOR_SECRET',
}
describe('.url', () => {
it('replaces the internal domain of the S3 `Location` with a public domain', () => {
const expectedUrl =
'https://your-public-gateway.com/iJ5iCYb-c6DnvQHTLrKcIlioWVk=/fsn1.your-objectstorage.com/ocelot-social-staging/original/f965ea15-1f6b-43aa-a535-927410e2585e-dsc02586.jpg'
expect(Image.url({ url: Location }, args, { config })).toEqual(expectedUrl)
})
})
describe('.transform', () => {
describe('resize transformations', () => {
const args = { width: 320 }
it('encodes `fit-in` imagor transformations in the URL', () => {
const expectedUrl =
'https://your-public-gateway.com/gg1VO_owYoOkltsIPNNFV7JcuUE=/fit-in/320x5000/fsn1.your-objectstorage.com/ocelot-social-staging/original/f965ea15-1f6b-43aa-a535-927410e2585e-dsc02586.jpg'
expect(Image.transform({ url: Location }, args, { config })).toEqual(expectedUrl)
})
})
})
})

View File

@ -9,27 +9,28 @@ type UrlResolver = (
args: { width?: number; height?: number },
{
config: { S3_PUBLIC_GATEWAY },
}: Context,
}: Pick<Context, 'config'>,
) => string
const changeDomain: (opts: { transformations: UrlResolver[] }) => UrlResolver =
({ transformations }) =>
(parent, _args, context) => {
({ url }, _args, context) => {
const { config } = context
const { S3_PUBLIC_GATEWAY, AWS_ENDPOINT } = config
if (!(S3_PUBLIC_GATEWAY && AWS_ENDPOINT)) {
return parent.url
return url
}
if (new URL(parent.url).host !== new URL(AWS_ENDPOINT).host) {
const originalUrl = new URL(url, AWS_ENDPOINT) // some S3 object storages return invalid URLs as location, so put the AWS_ENDPOINT as `base`
if (originalUrl.host !== new URL(AWS_ENDPOINT).host) {
// In this case it's an external upload - maybe seeded?
// Let's not change the URL in this case
return parent.url
return url
}
const publicUrl = new URL(S3_PUBLIC_GATEWAY)
publicUrl.pathname = new URL(parent.url).pathname
const url = publicUrl.href
return chain(...transformations)({ url }, _args, context)
publicUrl.pathname = originalUrl.pathname
const newUrl = publicUrl.href
return chain(...transformations)({ url: newUrl }, _args, context)
}
const sign: UrlResolver = ({ url }, _args, { config: { IMAGOR_SECRET } }) => {