Skip to content

Commit d2393dc

Browse files
committed
Merge branch 'fix/image-proxy-logic' of https://github.com/alexdln/npmx.dev into fix/image-proxy-logic
2 parents 05fc15b + 34622e4 commit d2393dc

1 file changed

Lines changed: 83 additions & 14 deletions

File tree

server/api/registry/image-proxy/index.get.ts

Lines changed: 83 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,14 @@ export default defineEventHandler(async event => {
5858
// Verify HMAC signature to ensure this URL was generated server-side
5959
const { imageProxySecret } = useRuntimeConfig()
6060
if (!imageProxySecret || !verifyImageUrl(url, sig, imageProxySecret)) {
61-
return {place: 'sig', url, sig, reqUrl: event.node.req.url, reqOrigUrl: event.node.req.originalUrl, imageProxySecret}
61+
return {
62+
place: 'sig',
63+
url,
64+
sig,
65+
reqUrl: event.node.req.url,
66+
reqOrigUrl: event.node.req.originalUrl,
67+
imageProxySecret,
68+
}
6269
// throw createError({
6370
// statusCode: 403,
6471
// message: 'Invalid signature.',
@@ -67,7 +74,13 @@ export default defineEventHandler(async event => {
6774

6875
// Validate URL syntactically
6976
if (!isAllowedImageUrl(url)) {
70-
return {place: 'isAllowedImageUrl', url, sig, reqUrl: event.node.req.url, reqOrigUrl: event.node.req.originalUrl}
77+
return {
78+
place: 'isAllowedImageUrl',
79+
url,
80+
sig,
81+
reqUrl: event.node.req.url,
82+
reqOrigUrl: event.node.req.originalUrl,
83+
}
7184
// throw createError({
7285
// statusCode: 400,
7386
// message: 'Invalid or disallowed image URL.',
@@ -77,7 +90,13 @@ export default defineEventHandler(async event => {
7790
// Resolve hostname via DNS and validate the resolved IP is not private.
7891
// This prevents DNS rebinding attacks where a hostname resolves to a private IP.
7992
if (!(await resolveAndValidateHost(url))) {
80-
return {place: 'resolveAndValidateHost', url, sig, reqUrl: event.node.req.url, reqOrigUrl: event.node.req.originalUrl}
93+
return {
94+
place: 'resolveAndValidateHost',
95+
url,
96+
sig,
97+
reqUrl: event.node.req.url,
98+
reqOrigUrl: event.node.req.originalUrl,
99+
}
81100
// throw createError({
82101
// statusCode: 400,
83102
// message: 'Invalid or disallowed image URL.',
@@ -115,15 +134,27 @@ export default defineEventHandler(async event => {
115134

116135
// Validate the redirect target before following it
117136
if (!isAllowedImageUrl(redirectUrl)) {
118-
return {place: 'isAllowedImageUrl 2', url, sig, reqUrl: event.node.req.url, reqOrigUrl: event.node.req.originalUrl}
137+
return {
138+
place: 'isAllowedImageUrl 2',
139+
url,
140+
sig,
141+
reqUrl: event.node.req.url,
142+
reqOrigUrl: event.node.req.originalUrl,
143+
}
119144
// throw createError({
120145
// statusCode: 400,
121146
// message: 'Redirect to disallowed URL.',
122147
// })
123148
}
124149

125150
if (!(await resolveAndValidateHost(redirectUrl))) {
126-
return {place: 'resolveAndValidateHost 2', url, sig, reqUrl: event.node.req.url, reqOrigUrl: event.node.req.originalUrl}
151+
return {
152+
place: 'resolveAndValidateHost 2',
153+
url,
154+
sig,
155+
reqUrl: event.node.req.url,
156+
reqOrigUrl: event.node.req.originalUrl,
157+
}
127158
// throw createError({
128159
// statusCode: 400,
129160
// message: 'Redirect to disallowed URL.',
@@ -136,7 +167,13 @@ export default defineEventHandler(async event => {
136167
}
137168

138169
if (!response) {
139-
return {place: 'response', url, sig, reqUrl: event.node.req.url, reqOrigUrl: event.node.req.originalUrl}
170+
return {
171+
place: 'response',
172+
url,
173+
sig,
174+
reqUrl: event.node.req.url,
175+
reqOrigUrl: event.node.req.originalUrl,
176+
}
140177
// throw createError({
141178
// statusCode: 502,
142179
// message: 'Failed to fetch image.',
@@ -146,19 +183,31 @@ export default defineEventHandler(async event => {
146183
// Check if we exhausted the redirect limit
147184
if (REDIRECT_STATUSES.has(response.status)) {
148185
await response.body?.cancel()
149-
return {place: 'response 2', url, sig, reqUrl: event.node.req.url, reqOrigUrl: event.node.req.originalUrl}
186+
return {
187+
place: 'response 2',
188+
url,
189+
sig,
190+
reqUrl: event.node.req.url,
191+
reqOrigUrl: event.node.req.originalUrl,
192+
}
150193
// throw createError({
151194
// statusCode: 502,
152-
// message: 'Too many redirects.',
195+
// message: 'Too many redirects.',
153196
// })
154197
}
155198

156199
if (!response.ok) {
157200
await response.body?.cancel()
158-
return {place: 'response 3', url, sig, reqUrl: event.node.req.url, reqOrigUrl: event.node.req.originalUrl}
201+
return {
202+
place: 'response 3',
203+
url,
204+
sig,
205+
reqUrl: event.node.req.url,
206+
reqOrigUrl: event.node.req.originalUrl,
207+
}
159208
// throw createError({
160209
// statusCode: response.status === 404 ? 404 : 502,
161-
// message: `Failed to fetch image: ${response.status}`,
210+
// message: `Failed to fetch image: ${response.status}`,
162211
// })
163212
}
164213

@@ -167,10 +216,16 @@ export default defineEventHandler(async event => {
167216
// Allow raster/vector image content types (we don't inject external content into DOM, so SVG is allowed too)
168217
if (!contentType.startsWith('image/')) {
169218
await response.body?.cancel()
170-
return {place: 'contentType', url, sig, reqUrl: event.node.req.url, reqOrigUrl: event.node.req.originalUrl}
219+
return {
220+
place: 'contentType',
221+
url,
222+
sig,
223+
reqUrl: event.node.req.url,
224+
reqOrigUrl: event.node.req.originalUrl,
225+
}
171226
// throw createError({
172227
// statusCode: 400,
173-
// message: 'URL does not point to an allowed image type.',
228+
// message: 'URL does not point to an allowed image type.',
174229
// })
175230
}
176231

@@ -233,11 +288,25 @@ export default defineEventHandler(async event => {
233288
} catch (error: unknown) {
234289
// Re-throw H3 errors
235290
if (error && typeof error === 'object' && 'statusCode' in error) {
236-
return {place: 'error', url, sig, reqUrl: event.node.req.url, reqOrigUrl: event.node.req.originalUrl, error}
291+
return {
292+
place: 'error',
293+
url,
294+
sig,
295+
reqUrl: event.node.req.url,
296+
reqOrigUrl: event.node.req.originalUrl,
297+
error,
298+
}
237299
// throw error
238300
}
239301

240-
return {place: 'error 2', url, sig, reqUrl: event.node.req.url, reqOrigUrl: event.node.req.originalUrl, error}
302+
return {
303+
place: 'error 2',
304+
url,
305+
sig,
306+
reqUrl: event.node.req.url,
307+
reqOrigUrl: event.node.req.originalUrl,
308+
error,
309+
}
241310
// throw createError({
242311
// statusCode: 502,
243312
// message: 'Failed to proxy image.',

0 commit comments

Comments
 (0)