diff --git a/frontend/src/pages/_app.tsx b/frontend/src/pages/_app.tsx index c6829bfdf..470f9feb5 100644 --- a/frontend/src/pages/_app.tsx +++ b/frontend/src/pages/_app.tsx @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ @@ -14,14 +14,16 @@ import { UiNotificationBoundary } from '../components/notifications/ui-notificat import { StoreProvider } from '../redux/store-provider' import { BaseUrlFromEnvExtractor } from '../utils/base-url-from-env-extractor' import { configureLuxon } from '../utils/configure-luxon' -import { ExpectedOriginBoundary } from '../utils/uri-origin-boundary' -import type { AppInitialProps, AppProps } from 'next/app' +import { determineCurrentOrigin } from '../utils/determine-current-origin' +import { ExpectedOriginBoundary } from '../utils/expected-origin-boundary' +import type { AppContext, AppInitialProps, AppProps } from 'next/app' import React from 'react' configureLuxon() interface AppPageProps { baseUrls: BaseUrls | undefined + currentOrigin: string | undefined } /** @@ -31,8 +33,8 @@ interface AppPageProps { function HedgeDocApp({ Component, pageProps }: AppProps) { return ( - - + + @@ -41,20 +43,22 @@ function HedgeDocApp({ Component, pageProps }: AppProps) { - - + + ) } -const baseUrlFromEnvExtractor: BaseUrlFromEnvExtractor = new BaseUrlFromEnvExtractor() +const baseUrlFromEnvExtractor = new BaseUrlFromEnvExtractor() -HedgeDocApp.getInitialProps = (): AppInitialProps => { +HedgeDocApp.getInitialProps = ({ ctx }: AppContext): AppInitialProps => { const baseUrls = baseUrlFromEnvExtractor.extractBaseUrls().orElse(undefined) + const currentOrigin = determineCurrentOrigin(ctx) return { pageProps: { - baseUrls + baseUrls, + currentOrigin } } } diff --git a/frontend/src/utils/determine-current-origin.ts b/frontend/src/utils/determine-current-origin.ts new file mode 100644 index 000000000..573899f95 --- /dev/null +++ b/frontend/src/utils/determine-current-origin.ts @@ -0,0 +1,33 @@ +/* + * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) + * + * SPDX-License-Identifier: AGPL-3.0-only + */ +import { isClientSideRendering } from './is-client-side-rendering' +import type { NextPageContext } from 'next' + +/** + * Determines the location origin of the current request. + * Client side rendering will use the browsers window location. + * Server side rendering will use the http request. + * + * @param context The next page context that contains the http headers + * @return the determined request origin. Will be undefined if no origin could be determined. + */ +export const determineCurrentOrigin = (context: NextPageContext): string | undefined => { + if (isClientSideRendering()) { + return window.location.origin + } + const headers = context.req?.headers + if (headers === undefined) { + return undefined + } + + const protocol = headers['x-forwarded-proto'] ?? 'http' + const host = headers['x-forwarded-host'] ?? headers['host'] + if (host === undefined) { + return undefined + } + + return `${protocol as string}://${host as string}` +} diff --git a/frontend/src/utils/uri-origin-boundary.tsx b/frontend/src/utils/expected-origin-boundary.tsx similarity index 52% rename from frontend/src/utils/uri-origin-boundary.tsx rename to frontend/src/utils/expected-origin-boundary.tsx index 4ce959916..37dc27899 100644 --- a/frontend/src/utils/uri-origin-boundary.tsx +++ b/frontend/src/utils/expected-origin-boundary.tsx @@ -1,25 +1,37 @@ /* - * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ import { useBaseUrl } from '../hooks/common/use-base-url' -import { isClientSideRendering } from './is-client-side-rendering' import React, { Fragment, useMemo } from 'react' import type { PropsWithChildren } from 'react' +export interface ExpectedOriginBoundaryProps { + currentOrigin?: string +} + /** * Checks if the url of the current browser window matches the expected origin. * This is necessary to ensure that the render endpoint is only opened from the rendering origin. * * @param children The children react element that should be rendered if the origin is correct + * @param currentOrigin the current origin from client or server side rendering context */ -export const ExpectedOriginBoundary: React.FC = ({ children }) => { +export const ExpectedOriginBoundary: React.FC> = ({ + children, + currentOrigin +}) => { const baseUrl = useBaseUrl() const expectedOrigin = useMemo(() => new URL(baseUrl).origin, [baseUrl]) - if (isClientSideRendering() && window.location.origin !== expectedOrigin) { - return {`You can't open this page using this URL. For this endpoint "${expectedOrigin}" is expected.`} + if (currentOrigin !== expectedOrigin) { + return ( + {`You can't open this page using this URL. For this endpoint "${expectedOrigin}" is expected.`} + ) } else { return {children} }