Skip to content

Commit 611af82

Browse files
authored
fix: runtime secret override via NUXT_OG_IMAGE_SECRET (#593)
1 parent 9a4ca09 commit 611af82

7 files changed

Lines changed: 28 additions & 6 deletions

File tree

src/module.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1558,6 +1558,17 @@ export const rootDir = ${JSON.stringify(nuxt.options.rootDir)}`
15581558
// @ts-expect-error untyped
15591559
nuxt.options.runtimeConfig['nuxt-og-image'] = runtimeConfig
15601560

1561+
// Top-level alias so `NUXT_OG_IMAGE_SECRET` env var maps automatically via
1562+
// Nuxt's standard runtime override convention (NUXT_<KEY> -> runtimeConfig.<key>).
1563+
// Read by useOgImageRuntimeConfig and prefers this value over security.secret
1564+
// when set, allowing runtime overrides on platforms like Cloudflare Workers
1565+
// where env bindings are surfaced through the event context.
1566+
const existingOgImageCfg = (nuxt.options.runtimeConfig as Record<string, any>).ogImage
1567+
;(nuxt.options.runtimeConfig as Record<string, any>).ogImage = {
1568+
...(existingOgImageCfg && typeof existingOgImageCfg === 'object' ? existingOgImageCfg : {}),
1569+
secret: (existingOgImageCfg as any)?.secret || config.security?.secret || process.env.NUXT_OG_IMAGE_SECRET || '',
1570+
}
1571+
15611572
// Non-sensitive subset exposed to the browser so defineOgImage can refresh
15621573
// og:image meta tags on SPA navigation (#567). `defaults` feed the SSG
15631574
// URL-rebuild fallback path; `hasServerRuntime` gates the `/_og/r/` resolver

src/runtime/server/og-image/browser/screenshot.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ async function takeScreenshot(page: Page, selector: string | undefined, options:
8181
}
8282

8383
export async function createScreenshot({ basePath, e, options, extension, timings }: OgImageRenderEventContext, browser: Browser): Promise<Buffer> {
84-
const runtimeConfig = useOgImageRuntimeConfig()
84+
const runtimeConfig = useOgImageRuntimeConfig(e)
8585
const { colorPreference, defaults, security } = runtimeConfig
8686
// For browser renderer, we need to load the HTML template with options encoded in URL
8787
const path = options.component === 'PageScreenshot' ? basePath : buildOgImageUrl(options, 'html', false, defaults, security?.secret || undefined).url

src/runtime/server/og-image/context.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export function resolvePathCacheKey(e: H3Event, path: string, resolvedOptions?:
4848
}
4949

5050
export async function resolveContext(e: H3Event): Promise<H3Error | OgImageRenderEventContext> {
51-
const runtimeConfig = useOgImageRuntimeConfig()
51+
const runtimeConfig = useOgImageRuntimeConfig(e)
5252
// we need to resolve the url ourselves as Nitro may be stripping the base
5353
const resolvePathWithBase = createSitePathResolver(e, {
5454
absolute: false,

src/runtime/server/routes/debug.json.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { useOgImageRuntimeConfig } from '../utils'
1212
export default defineEventHandler(async (e) => {
1313
// set json header
1414
setHeader(e, 'Content-Type', 'application/json')
15-
const runtimeConfig = useOgImageRuntimeConfig()
15+
const runtimeConfig = useOgImageRuntimeConfig(e)
1616
return {
1717
siteConfigUrl: getSiteConfig(e as any).url,
1818
origin: getNitroOrigin(e),

src/runtime/server/routes/resolve.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ function resolveTargetPath(event: H3Event): string {
5252
}
5353

5454
export default defineEventHandler(async (event) => {
55-
const runtimeConfig = useOgImageRuntimeConfig()
55+
const runtimeConfig = useOgImageRuntimeConfig(event)
5656
const security = runtimeConfig.security
5757

5858
// Origin restriction: mirror imageEventHandler — block runtime requests from

src/runtime/server/util/eventHandlers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ async function renderOgImage(e: H3Event, ctx: Exclude<Awaited<ReturnType<typeof
3333
const timings = ctx.timings
3434

3535
const { isDevToolsContextRequest, extension, renderer } = ctx
36-
const { debug, baseCacheKey, security } = useOgImageRuntimeConfig()
36+
const { debug, baseCacheKey, security } = useOgImageRuntimeConfig(e)
3737

3838
// Origin restriction: block runtime requests from unknown hosts.
3939
// Loopback requests (localhost, 127.0.0.1, ::1) are allowed only when URL

src/runtime/server/utils.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,20 @@ export function getOgImagePath(_pagePath: string, _options?: Partial<OgImageOpti
3636

3737
export function useOgImageRuntimeConfig(e?: H3Event) {
3838
const c = useRuntimeConfig(e)
39+
const moduleCfg = (c['nuxt-og-image'] as Record<string, any> | undefined) || {}
40+
// Top-level `ogImage.secret` is populated by Nuxt's standard env override
41+
// (`NUXT_OG_IMAGE_SECRET`) and takes precedence over the build-time
42+
// `security.secret` so deployments can rotate the secret without rebuilding.
43+
// Passing the event matters on platforms like Cloudflare Workers where env
44+
// bindings are only resolved when an event is available.
45+
const overrideSecret = (c as Record<string, any>).ogImage?.secret as string | undefined
46+
const security = overrideSecret
47+
? { ...(moduleCfg.security || {}), secret: overrideSecret }
48+
: moduleCfg.security
3949
return {
4050
defaults: {},
41-
...(c['nuxt-og-image'] as Record<string, any>),
51+
...moduleCfg,
52+
security,
4253
app: {
4354
baseURL: c.app.baseURL,
4455
},

0 commit comments

Comments
 (0)