Skip to content

Commit

Permalink
feat: validate external domains (#343)
Browse files Browse the repository at this point in the history
Co-authored-by: pooya parsa <pyapar@gmail.com>
  • Loading branch information
farnabaz and pi0 authored Jun 29, 2021
1 parent 4711fee commit bee0040
Show file tree
Hide file tree
Showing 6 changed files with 27 additions and 14 deletions.
7 changes: 6 additions & 1 deletion src/module.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { resolve } from 'upath'
import defu from 'defu'

import { parseURL } from 'ufo'
import type { Module } from '@nuxt/types'
import { setupStaticGeneration } from './generate'
import { resolveProviders, detectProvider } from './provider'
Expand Down Expand Up @@ -34,6 +34,11 @@ const imageModule: Module<ModuleOptions> = async function imageModule (moduleOpt

const options: ModuleOptions = defu(moduleOptions, nuxt.options.image, defaults)

// Normalize domains to hostname
options.domains = options.domains
.map(domain => parseURL(domain, 'https://').host)
.filter(Boolean) as string[]

options.provider = detectProvider(options.provider, nuxt.options.target === 'static')
options[options.provider] = options[options.provider] || {}

Expand Down
3 changes: 1 addition & 2 deletions src/provider.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { normalize, resolve, dirname } from 'upath'
import { writeJson, mkdirp } from 'fs-extra'
import { parseURL } from 'ufo'
import { hash } from './utils'
import type { ModuleOptions, InputProvider, ImageModuleProvider, ProviderSetup } from './types'
import { ipxSetup } from './ipx'
Expand Down Expand Up @@ -31,7 +30,7 @@ export const providerSetup: Record<string, ProviderSetup> = {
const imagesConfig = resolve(nuxt.options.rootDir, '.vercel_build_output/config/images.json')
await mkdirp(dirname(imagesConfig))
await writeJson(imagesConfig, {
domains: moduleOptions.domains.map(domain => parseURL(domain, 'https://').host),
domains: moduleOptions.domains,
sizes: Array.from(new Set(Object.values(moduleOptions.screens || {})))
})
}
Expand Down
12 changes: 12 additions & 0 deletions src/runtime/image.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import defu from 'defu'
import { hasProtocol, parseURL } from 'ufo'
import type { ImageOptions, ImageSizesOptions, CreateImageOptions, ResolvedImage, MapToStatic, ImageCTX, $Img } from '../types/image'
import { imageMeta } from './utils/meta'
import { parseSize } from './utils'
Expand Down Expand Up @@ -98,6 +99,17 @@ function resolveImage (ctx: ImageCTX, input: string, options: ImageOptions): Res
const { provider, defaults } = getProvider(ctx, options.provider || ctx.options.provider)
const preset = getPreset(ctx, options.preset)

// Externalize remote images if domain does not match with `domains`
if (provider.validateDomains && hasProtocol(input)) {
const inputHost = parseURL(input).host
// Domains are normalized to hostname in module
if (!ctx.options.domains.find(d => d === inputHost)) {
return {
url: input
}
}
}

const _options: ImageOptions = defu(options, preset, defaults)
_options.modifiers = { ..._options.modifiers }
const expectedFormat = _options.modifiers.format
Expand Down
14 changes: 4 additions & 10 deletions src/runtime/providers/ipx.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ProviderGetImage } from 'src'
import { joinURL, encodeQueryItem, encodePath, hasProtocol } from 'ufo'
import { joinURL, encodeQueryItem, encodePath } from 'ufo'
import { createOperationsGenerator } from '~image'

const operationsGenerator = createOperationsGenerator({
Expand All @@ -16,7 +16,7 @@ const operationsGenerator = createOperationsGenerator({
formatter: (key, val) => encodeQueryItem(key, val)
})

export const getImage: ProviderGetImage = (src, { modifiers = {}, baseURL = '/_ipx' } = {}, { options: { domains = [] } }) => {
export const getImage: ProviderGetImage = (src, { modifiers = {}, baseURL = '/_ipx' } = {}) => {
if (modifiers.width && modifiers.height) {
modifiers.resize = `${modifiers.width}_${modifiers.height}`
delete modifiers.width
Expand All @@ -25,15 +25,9 @@ export const getImage: ProviderGetImage = (src, { modifiers = {}, baseURL = '/_i

const params = operationsGenerator(modifiers)

if (hasProtocol(src)) {
if (!domains.find((d: string) => src.startsWith(d))) {
return {
url: src
}
}
}

return {
url: joinURL(baseURL, encodePath(src) + (params ? '?' + params : ''))
}
}

export const validateDomains = true
2 changes: 2 additions & 0 deletions src/runtime/providers/vercel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,5 @@ export const getImage: ProviderGetImage = (src, { modifiers, baseURL = '/_vercel
})
}
}

export const validateDomains = true
3 changes: 2 additions & 1 deletion src/types/image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export type ProviderGetImage = (src: string, options: ImageOptions, ctx: ImageCT
export interface ImageProvider {
defaults?: any
getImage: ProviderGetImage
validateDomains?: Boolean
}

export interface CreateImageOptions {
Expand All @@ -35,7 +36,7 @@ export interface CreateImageOptions {
presets: { [name: string]: ImageOptions }
provider: string
screens?: Record<string, number>,
domains?: string[]
domains: string[]
}

export interface ImageInfo {
Expand Down

0 comments on commit bee0040

Please sign in to comment.