mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2024-11-22 01:36:29 -05:00
fix: expected origin boundary works now with initial props
Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
parent
8977100830
commit
9771ffcf00
3 changed files with 64 additions and 15 deletions
|
@ -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
|
* 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 { StoreProvider } from '../redux/store-provider'
|
||||||
import { BaseUrlFromEnvExtractor } from '../utils/base-url-from-env-extractor'
|
import { BaseUrlFromEnvExtractor } from '../utils/base-url-from-env-extractor'
|
||||||
import { configureLuxon } from '../utils/configure-luxon'
|
import { configureLuxon } from '../utils/configure-luxon'
|
||||||
import { ExpectedOriginBoundary } from '../utils/uri-origin-boundary'
|
import { determineCurrentOrigin } from '../utils/determine-current-origin'
|
||||||
import type { AppInitialProps, AppProps } from 'next/app'
|
import { ExpectedOriginBoundary } from '../utils/expected-origin-boundary'
|
||||||
|
import type { AppContext, AppInitialProps, AppProps } from 'next/app'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
configureLuxon()
|
configureLuxon()
|
||||||
|
|
||||||
interface AppPageProps {
|
interface AppPageProps {
|
||||||
baseUrls: BaseUrls | undefined
|
baseUrls: BaseUrls | undefined
|
||||||
|
currentOrigin: string | undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,8 +33,8 @@ interface AppPageProps {
|
||||||
function HedgeDocApp({ Component, pageProps }: AppProps<AppPageProps>) {
|
function HedgeDocApp({ Component, pageProps }: AppProps<AppPageProps>) {
|
||||||
return (
|
return (
|
||||||
<BaseUrlContextProvider baseUrls={pageProps.baseUrls}>
|
<BaseUrlContextProvider baseUrls={pageProps.baseUrls}>
|
||||||
<StoreProvider>
|
<ExpectedOriginBoundary currentOrigin={pageProps.currentOrigin}>
|
||||||
<ExpectedOriginBoundary>
|
<StoreProvider>
|
||||||
<BaseHead />
|
<BaseHead />
|
||||||
<ApplicationLoader>
|
<ApplicationLoader>
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
|
@ -41,20 +43,22 @@ function HedgeDocApp({ Component, pageProps }: AppProps<AppPageProps>) {
|
||||||
</UiNotificationBoundary>
|
</UiNotificationBoundary>
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
</ApplicationLoader>
|
</ApplicationLoader>
|
||||||
</ExpectedOriginBoundary>
|
</StoreProvider>
|
||||||
</StoreProvider>
|
</ExpectedOriginBoundary>
|
||||||
</BaseUrlContextProvider>
|
</BaseUrlContextProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const baseUrlFromEnvExtractor: BaseUrlFromEnvExtractor = new BaseUrlFromEnvExtractor()
|
const baseUrlFromEnvExtractor = new BaseUrlFromEnvExtractor()
|
||||||
|
|
||||||
HedgeDocApp.getInitialProps = (): AppInitialProps<AppPageProps> => {
|
HedgeDocApp.getInitialProps = ({ ctx }: AppContext): AppInitialProps<AppPageProps> => {
|
||||||
const baseUrls = baseUrlFromEnvExtractor.extractBaseUrls().orElse(undefined)
|
const baseUrls = baseUrlFromEnvExtractor.extractBaseUrls().orElse(undefined)
|
||||||
|
const currentOrigin = determineCurrentOrigin(ctx)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
pageProps: {
|
pageProps: {
|
||||||
baseUrls
|
baseUrls,
|
||||||
|
currentOrigin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
33
frontend/src/utils/determine-current-origin.ts
Normal file
33
frontend/src/utils/determine-current-origin.ts
Normal file
|
@ -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}`
|
||||||
|
}
|
|
@ -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
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
import { useBaseUrl } from '../hooks/common/use-base-url'
|
import { useBaseUrl } from '../hooks/common/use-base-url'
|
||||||
import { isClientSideRendering } from './is-client-side-rendering'
|
|
||||||
import React, { Fragment, useMemo } from 'react'
|
import React, { Fragment, useMemo } from 'react'
|
||||||
import type { PropsWithChildren } 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.
|
* 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.
|
* 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 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<PropsWithChildren> = ({ children }) => {
|
export const ExpectedOriginBoundary: React.FC<PropsWithChildren<ExpectedOriginBoundaryProps>> = ({
|
||||||
|
children,
|
||||||
|
currentOrigin
|
||||||
|
}) => {
|
||||||
const baseUrl = useBaseUrl()
|
const baseUrl = useBaseUrl()
|
||||||
const expectedOrigin = useMemo(() => new URL(baseUrl).origin, [baseUrl])
|
const expectedOrigin = useMemo(() => new URL(baseUrl).origin, [baseUrl])
|
||||||
|
|
||||||
if (isClientSideRendering() && window.location.origin !== expectedOrigin) {
|
if (currentOrigin !== expectedOrigin) {
|
||||||
return <span>{`You can't open this page using this URL. For this endpoint "${expectedOrigin}" is expected.`}</span>
|
return (
|
||||||
|
<span
|
||||||
|
className={
|
||||||
|
'text-white bg-dark'
|
||||||
|
}>{`You can't open this page using this URL. For this endpoint "${expectedOrigin}" is expected.`}</span>
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
return <Fragment>{children}</Fragment>
|
return <Fragment>{children}</Fragment>
|
||||||
}
|
}
|
Loading…
Reference in a new issue