From ae61e7e0bca4a674661f925aa465c16a0d97194e Mon Sep 17 00:00:00 2001 From: Shu Ding Date: Thu, 28 Mar 2024 23:40:23 +0100 Subject: [PATCH] Move key generation to the earlier stage (#63832) Currently, the encryption key for Server Actions is generated during the manifest creation. This PR moves it to be in the same position as the build ID generation, and we will later leverage that key for other use cases. Closes NEXT-2959 --- packages/next/src/build/build-context.ts | 1 + packages/next/src/build/index.ts | 12 +++++++++++- packages/next/src/build/webpack-build/impl.ts | 1 + packages/next/src/build/webpack-config.ts | 3 +++ .../webpack/plugins/flight-client-entry-plugin.ts | 8 ++++---- .../next/src/server/dev/hot-reloader-turbopack.ts | 7 ++++++- .../next/src/server/dev/hot-reloader-webpack.ts | 6 ++++++ .../src/server/dev/turbopack/manifest-loader.ts | 15 ++++++++++++--- .../server/lib/router-utils/setup-dev-bundler.ts | 2 ++ 9 files changed, 46 insertions(+), 9 deletions(-) diff --git a/packages/next/src/build/build-context.ts b/packages/next/src/build/build-context.ts index 0616d14e288ef..c6d3b120fccdd 100644 --- a/packages/next/src/build/build-context.ts +++ b/packages/next/src/build/build-context.ts @@ -54,6 +54,7 @@ export const NextBuildContext: Partial<{ // core fields dir: string buildId: string + encryptionKey: string config: NextConfigComplete appDir: string pagesDir: string diff --git a/packages/next/src/build/index.ts b/packages/next/src/build/index.ts index 51d2bd6cb87d7..d53fae0c421a9 100644 --- a/packages/next/src/build/index.ts +++ b/packages/next/src/build/index.ts @@ -182,6 +182,7 @@ import { TurbopackManifestLoader } from '../server/dev/turbopack/manifest-loader import type { Entrypoints } from '../server/dev/turbopack/types' import { buildCustomRoute } from '../lib/build-custom-route' import { createProgress } from './progress' +import { generateEncryptionKeyBase64 } from '../server/app-render/encryption-utils' interface ExperimentalBypassForInfo { experimentalBypassFor?: RouteHas[] @@ -765,6 +766,11 @@ export default async function build( pages: typeof pagesDir === 'string', } + // Generate a random encryption key for this build. + // This key is used to encrypt cross boundary values and can be used to generate hashes. + const encryptionKey = await generateEncryptionKeyBase64() + NextBuildContext.encryptionKey = encryptionKey + const isSrcDir = path .relative(dir, pagesDir || appDir || '') .startsWith('src') @@ -1396,7 +1402,11 @@ export default async function build( const currentEntryIssues: EntryIssuesMap = new Map() - const manifestLoader = new TurbopackManifestLoader({ buildId, distDir }) + const manifestLoader = new TurbopackManifestLoader({ + buildId, + distDir, + encryptionKey, + }) // TODO: implement this const emptyRewritesObjToBeImplemented = { diff --git a/packages/next/src/build/webpack-build/impl.ts b/packages/next/src/build/webpack-build/impl.ts index 2bbcf61ab8a20..19467f53497dd 100644 --- a/packages/next/src/build/webpack-build/impl.ts +++ b/packages/next/src/build/webpack-build/impl.ts @@ -106,6 +106,7 @@ export async function webpackBuildImpl( const commonWebpackOptions = { isServer: false, buildId: NextBuildContext.buildId!, + encryptionKey: NextBuildContext.encryptionKey!, config: config, appDir: NextBuildContext.appDir!, pagesDir: NextBuildContext.pagesDir!, diff --git a/packages/next/src/build/webpack-config.ts b/packages/next/src/build/webpack-config.ts index e5bc98fe7ce5f..d4d72858382ab 100644 --- a/packages/next/src/build/webpack-config.ts +++ b/packages/next/src/build/webpack-config.ts @@ -300,6 +300,7 @@ export default async function getBaseWebpackConfig( dir: string, { buildId, + encryptionKey, config, compilerType, dev = false, @@ -321,6 +322,7 @@ export default async function getBaseWebpackConfig( fetchCacheKeyPrefix, }: { buildId: string + encryptionKey: string config: NextConfigComplete compilerType: CompilerNameValues dev?: boolean @@ -1867,6 +1869,7 @@ export default async function getBaseWebpackConfig( appDir, dev, isEdgeServer, + encryptionKey, })), hasAppDir && !isClient && diff --git a/packages/next/src/build/webpack/plugins/flight-client-entry-plugin.ts b/packages/next/src/build/webpack/plugins/flight-client-entry-plugin.ts index bedc72129fe6a..4d2a5c3f43363 100644 --- a/packages/next/src/build/webpack/plugins/flight-client-entry-plugin.ts +++ b/packages/next/src/build/webpack/plugins/flight-client-entry-plugin.ts @@ -39,7 +39,6 @@ import { } from '../utils' import { normalizePathSep } from '../../../shared/lib/page-path/normalize-path-sep' import { getProxiedPluginState } from '../../build-context' -import { generateEncryptionKeyBase64 } from '../../../server/app-render/encryption-utils' import { PAGE_TYPES } from '../../../lib/page-types' import { isWebpackServerOnlyLayer } from '../../utils' @@ -47,6 +46,7 @@ interface Options { dev: boolean appDir: string isEdgeServer: boolean + encryptionKey: string } const PLUGIN_NAME = 'FlightClientEntryPlugin' @@ -166,6 +166,7 @@ function deduplicateCSSImportsForEntry(mergedCSSimports: CssImports) { export class FlightClientEntryPlugin { dev: boolean appDir: string + encryptionKey: string isEdgeServer: boolean assetPrefix: string @@ -174,6 +175,7 @@ export class FlightClientEntryPlugin { this.appDir = options.appDir this.isEdgeServer = options.isEdgeServer this.assetPrefix = !this.dev && !this.isEdgeServer ? '../' : '' + this.encryptionKey = options.encryptionKey } apply(compiler: webpack.Compiler) { @@ -1000,9 +1002,7 @@ export class FlightClientEntryPlugin { { node: serverActions, edge: edgeServerActions, - - // Assign encryption - encryptionKey: await generateEncryptionKeyBase64(this.dev), + encryptionKey: this.encryptionKey, }, null, this.dev ? 2 : undefined diff --git a/packages/next/src/server/dev/hot-reloader-turbopack.ts b/packages/next/src/server/dev/hot-reloader-turbopack.ts index 0f130cf751c34..79d90d33b1b7f 100644 --- a/packages/next/src/server/dev/hot-reloader-turbopack.ts +++ b/packages/next/src/server/dev/hot-reloader-turbopack.ts @@ -79,6 +79,7 @@ import { splitEntryKey, } from './turbopack/entry-key' import { FAST_REFRESH_RUNTIME_RELOAD } from './messages' +import { generateEncryptionKeyBase64 } from '../app-render/encryption-utils' const wsServer = new ws.Server({ noServer: true }) const isTestMode = !!( @@ -161,7 +162,11 @@ export async function createHotReloaderTurbopack( const currentTopLevelIssues: TopLevelIssuesMap = new Map() const currentEntryIssues: EntryIssuesMap = new Map() - const manifestLoader = new TurbopackManifestLoader({ buildId, distDir }) + const manifestLoader = new TurbopackManifestLoader({ + buildId, + distDir, + encryptionKey: await generateEncryptionKeyBase64(), + }) // Dev specific const changeSubscriptions: ChangeSubscriptions = new Map() diff --git a/packages/next/src/server/dev/hot-reloader-webpack.ts b/packages/next/src/server/dev/hot-reloader-webpack.ts index 566936f6fa680..7de83535a7919 100644 --- a/packages/next/src/server/dev/hot-reloader-webpack.ts +++ b/packages/next/src/server/dev/hot-reloader-webpack.ts @@ -230,6 +230,7 @@ export default class HotReloaderWebpack implements NextJsHotReloaderInterface { private hasPagesRouterEntrypoints: boolean private dir: string private buildId: string + private encryptionKey: string private interceptors: any[] private pagesDir?: string private distDir: string @@ -271,6 +272,7 @@ export default class HotReloaderWebpack implements NextJsHotReloaderInterface { pagesDir, distDir, buildId, + encryptionKey, previewProps, rewrites, appDir, @@ -280,6 +282,7 @@ export default class HotReloaderWebpack implements NextJsHotReloaderInterface { pagesDir?: string distDir: string buildId: string + encryptionKey: string previewProps: __ApiPreviewProps rewrites: CustomRoutes['rewrites'] appDir?: string @@ -290,6 +293,7 @@ export default class HotReloaderWebpack implements NextJsHotReloaderInterface { this.hasAppRouterEntrypoints = false this.hasPagesRouterEntrypoints = false this.buildId = buildId + this.encryptionKey = encryptionKey this.dir = dir this.interceptors = [] this.pagesDir = pagesDir @@ -615,6 +619,7 @@ export default class HotReloaderWebpack implements NextJsHotReloaderInterface { const commonWebpackOptions = { dev: true, buildId: this.buildId, + encryptionKey: this.encryptionKey, config: this.config, pagesDir: this.pagesDir, rewrites: this.rewrites, @@ -671,6 +676,7 @@ export default class HotReloaderWebpack implements NextJsHotReloaderInterface { compilerType: COMPILER_NAMES.client, config: this.config, buildId: this.buildId, + encryptionKey: this.encryptionKey, pagesDir: this.pagesDir, rewrites: { beforeFiles: [], diff --git a/packages/next/src/server/dev/turbopack/manifest-loader.ts b/packages/next/src/server/dev/turbopack/manifest-loader.ts index f875e5c12e389..28d855a3873b3 100644 --- a/packages/next/src/server/dev/turbopack/manifest-loader.ts +++ b/packages/next/src/server/dev/turbopack/manifest-loader.ts @@ -7,7 +7,6 @@ import type { AppBuildManifest } from '../../../build/webpack/plugins/app-build- import type { PagesManifest } from '../../../build/webpack/plugins/pages-manifest-plugin' import { pathToRegexp } from 'next/dist/compiled/path-to-regexp' import type { ActionManifest } from '../../../build/webpack/plugins/flight-client-entry-plugin' -import { generateEncryptionKeyBase64 } from '../../app-render/encryption-utils' import type { NextFontManifest } from '../../../build/webpack/plugins/next-font-manifest-plugin' import type { LoadableManifest } from '../../load-components' import { @@ -86,13 +85,23 @@ export class TurbopackManifestLoader { private middlewareManifests: Map = new Map() private pagesManifests: Map = new Map() + private encryptionKey: string private readonly distDir: string private readonly buildId: string - constructor({ distDir, buildId }: { buildId: string; distDir: string }) { + constructor({ + distDir, + buildId, + encryptionKey, + }: { + buildId: string + distDir: string + encryptionKey: string + }) { this.distDir = distDir this.buildId = buildId + this.encryptionKey = encryptionKey } delete(key: EntryKey) { @@ -123,7 +132,7 @@ export class TurbopackManifestLoader { const manifest: ActionManifest = { node: {}, edge: {}, - encryptionKey: await generateEncryptionKeyBase64(true), + encryptionKey: this.encryptionKey, } function mergeActionIds( diff --git a/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts b/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts index 49fa02208e578..f3eb481850a50 100644 --- a/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts +++ b/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts @@ -75,6 +75,7 @@ import { PAGE_TYPES } from '../../../lib/page-types' import { createHotReloaderTurbopack } from '../../dev/hot-reloader-turbopack' import { getErrorSource } from '../../../shared/lib/error-source' import type { StackFrame } from 'next/dist/compiled/stacktrace-parser' +import { generateEncryptionKeyBase64 } from '../../app-render/encryption-utils' export type SetupOpts = { renderServer: LazyRenderServerInstance @@ -162,6 +163,7 @@ async function startWatcher(opts: SetupOpts) { distDir: distDir, config: opts.nextConfig, buildId: 'development', + encryptionKey: await generateEncryptionKeyBase64(), telemetry: opts.telemetry, rewrites: opts.fsChecker.rewrites, previewProps: opts.fsChecker.prerenderManifest.preview,