mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2024-11-28 12:11:00 -05:00
fix(window post message communication): set target origin on creation
Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
parent
7f6da650d1
commit
f2fbf9e7ca
5 changed files with 27 additions and 20 deletions
|
@ -7,20 +7,25 @@
|
|||
import { MotdModal } from './motd-modal'
|
||||
import { act, render, screen } from '@testing-library/react'
|
||||
import * as fetchMotdModule from './fetch-motd'
|
||||
import type { CommonModalProps } from '../modals/common-modal'
|
||||
import * as CommonModalModule from '../modals/common-modal'
|
||||
import type { PropsWithChildren } from 'react'
|
||||
import React from 'react'
|
||||
import type { CommonModalProps } from '../modals/common-modal'
|
||||
import { mockI18n } from '../../markdown-renderer/test-utils/mock-i18n'
|
||||
import * as RenderIframeModule from '../../editor-page/renderer-pane/render-iframe'
|
||||
import { testId } from '../../../utils/test-id'
|
||||
import * as UseBaseUrlModule from '../../../hooks/common/use-base-url'
|
||||
|
||||
jest.mock('./fetch-motd')
|
||||
jest.mock('../modals/common-modal')
|
||||
jest.mock('../../editor-page/renderer-pane/render-iframe')
|
||||
jest.mock('../../../hooks/common/use-base-url')
|
||||
|
||||
describe('motd modal', () => {
|
||||
beforeAll(mockI18n)
|
||||
beforeAll(async () => {
|
||||
jest.spyOn(UseBaseUrlModule, 'useBaseUrl').mockImplementation(() => 'https://example.org')
|
||||
await mockI18n()
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
jest.resetAllMocks()
|
||||
|
|
|
@ -8,6 +8,7 @@ import type { PropsWithChildren } from 'react'
|
|||
import React, { createContext, useContext, useEffect, useMemo } from 'react'
|
||||
import { EditorToRendererCommunicator } from '../../render-page/window-post-message-communicator/editor-to-renderer-communicator'
|
||||
import { v4 as uuid } from 'uuid'
|
||||
import { ORIGIN, useBaseUrl } from '../../../hooks/common/use-base-url'
|
||||
|
||||
const EditorToRendererCommunicatorContext = createContext<EditorToRendererCommunicator | undefined>(undefined)
|
||||
|
||||
|
@ -29,7 +30,12 @@ export const useEditorToRendererCommunicator: () => EditorToRendererCommunicator
|
|||
* Provides a {@link EditorToRendererCommunicator editor to renderer communicator} for the child components via Context.
|
||||
*/
|
||||
export const EditorToRendererCommunicatorContextProvider: React.FC<PropsWithChildren> = ({ children }) => {
|
||||
const communicator = useMemo<EditorToRendererCommunicator>(() => new EditorToRendererCommunicator(uuid()), [])
|
||||
const rendererUrl = useBaseUrl(ORIGIN.RENDERER)
|
||||
|
||||
const communicator = useMemo<EditorToRendererCommunicator>(
|
||||
() => new EditorToRendererCommunicator(uuid(), new URL(rendererUrl).origin),
|
||||
[rendererUrl]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
const currentCommunicator = communicator
|
||||
|
|
|
@ -28,27 +28,27 @@ export const useRendererToEditorCommunicator: () => RendererToEditorCommunicator
|
|||
}
|
||||
|
||||
export const RendererToEditorCommunicatorContextProvider: React.FC<PropsWithChildren<unknown>> = ({ children }) => {
|
||||
const editorOrigin = useBaseUrl(ORIGIN.EDITOR)
|
||||
const editorUrl = useBaseUrl(ORIGIN.EDITOR)
|
||||
const uuid = useSingleStringUrlParameter('uuid', undefined)
|
||||
const communicator = useMemo<RendererToEditorCommunicator>(() => {
|
||||
if (uuid === undefined) {
|
||||
throw new Error('no uuid found in url!')
|
||||
} else {
|
||||
return new RendererToEditorCommunicator(uuid)
|
||||
return new RendererToEditorCommunicator(uuid, new URL(editorUrl).origin)
|
||||
}
|
||||
}, [uuid])
|
||||
}, [editorUrl, uuid])
|
||||
|
||||
useEffect(() => {
|
||||
const currentCommunicator = communicator
|
||||
|
||||
currentCommunicator.setMessageTarget(window.parent, new URL(editorOrigin).origin)
|
||||
currentCommunicator.setMessageTarget(window.parent)
|
||||
currentCommunicator.registerEventListener()
|
||||
currentCommunicator.enableCommunication()
|
||||
currentCommunicator.sendMessageToOtherSide({
|
||||
type: CommunicationMessageType.RENDERER_READY
|
||||
})
|
||||
return () => currentCommunicator?.unregisterEventListener()
|
||||
}, [communicator, editorOrigin])
|
||||
}, [communicator, editorUrl])
|
||||
|
||||
/**
|
||||
* Provides a {@link RendererToEditorCommunicator renderer to editor communicator} for the child components via Context.
|
||||
|
|
|
@ -23,7 +23,6 @@ import { useSendScrollState } from './hooks/use-send-scroll-state'
|
|||
import { Logger } from '../../../utils/logger'
|
||||
import { useEffectOnRenderTypeChange } from './hooks/use-effect-on-render-type-change'
|
||||
import { cypressAttribute, cypressId } from '../../../utils/cypress-attribute'
|
||||
import { ORIGIN, useBaseUrl } from '../../../hooks/common/use-base-url'
|
||||
import { ShowIf } from '../../common/show-if/show-if'
|
||||
import { WaitSpinner } from '../../common/wait-spinner/wait-spinner'
|
||||
import { useExtensionEventEmitter } from '../../markdown-renderer/hooks/use-extension-event-emitter'
|
||||
|
@ -69,7 +68,6 @@ export const RenderIframe: React.FC<RenderIframeProps> = ({
|
|||
}) => {
|
||||
const [rendererReady, setRendererReady] = useState<boolean>(false)
|
||||
const frameReference = useRef<HTMLIFrameElement>(null)
|
||||
const rendererBaseUrl = useBaseUrl(ORIGIN.RENDERER)
|
||||
const iframeCommunicator = useEditorToRendererCommunicator()
|
||||
const resetRendererReady = useCallback(() => {
|
||||
log.debug('Reset render status')
|
||||
|
@ -143,9 +141,7 @@ export const RenderIframe: React.FC<RenderIframeProps> = ({
|
|||
log.error('Load triggered without content window')
|
||||
return
|
||||
}
|
||||
const origin = new URL(rendererBaseUrl).origin
|
||||
log.debug(`Set iframecommunicator window with origin ${origin ?? 'undefined'}`)
|
||||
iframeCommunicator.setMessageTarget(otherWindow, origin)
|
||||
iframeCommunicator.setMessageTarget(otherWindow)
|
||||
iframeCommunicator.enableCommunication()
|
||||
iframeCommunicator.sendMessageToOtherSide({
|
||||
type: CommunicationMessageType.SET_BASE_CONFIGURATION,
|
||||
|
@ -155,7 +151,7 @@ export const RenderIframe: React.FC<RenderIframeProps> = ({
|
|||
}
|
||||
})
|
||||
setRendererReady(true)
|
||||
}, [iframeCommunicator, rendererBaseUrl, rendererType])
|
||||
}, [iframeCommunicator, rendererType])
|
||||
)
|
||||
|
||||
useEffectOnRenderTypeChange(rendererType, onIframeLoad)
|
||||
|
|
|
@ -35,13 +35,12 @@ export abstract class WindowPostMessageCommunicator<
|
|||
MESSAGES extends MessagePayload<RECEIVE_TYPE | SEND_TYPE>
|
||||
> {
|
||||
private messageTarget?: Window
|
||||
private targetOrigin?: string
|
||||
private communicationEnabled: boolean
|
||||
private readonly emitter: EventEmitter2 = new EventEmitter2()
|
||||
private readonly log: Logger
|
||||
private readonly boundListener: (event: MessageEvent) => void
|
||||
|
||||
public constructor(private uuid: string) {
|
||||
public constructor(private readonly uuid: string, private readonly targetOrigin: string) {
|
||||
this.boundListener = this.handleEvent.bind(this)
|
||||
this.communicationEnabled = false
|
||||
this.log = this.createLogger()
|
||||
|
@ -72,12 +71,10 @@ export abstract class WindowPostMessageCommunicator<
|
|||
* Messages can be sent as soon as the communication is enabled.
|
||||
*
|
||||
* @param otherSide The target {@link Window} that should receive the messages.
|
||||
* @param otherOrigin The origin from the URL of the target. If this isn't correct then the message sending will produce CORS errors.
|
||||
* @see enableCommunication
|
||||
*/
|
||||
public setMessageTarget(otherSide: Window, otherOrigin: string): void {
|
||||
public setMessageTarget(otherSide: Window): void {
|
||||
this.messageTarget = otherSide
|
||||
this.targetOrigin = otherOrigin
|
||||
this.communicationEnabled = false
|
||||
}
|
||||
|
||||
|
@ -86,7 +83,6 @@ export abstract class WindowPostMessageCommunicator<
|
|||
*/
|
||||
public unsetMessageTarget(): void {
|
||||
this.messageTarget = undefined
|
||||
this.targetOrigin = undefined
|
||||
this.communicationEnabled = false
|
||||
}
|
||||
|
||||
|
@ -152,6 +148,10 @@ export abstract class WindowPostMessageCommunicator<
|
|||
*/
|
||||
protected handleEvent(event: MessageEvent<MessagePayloadWithUuid<RECEIVE_TYPE>>): void {
|
||||
if (event.origin !== this.targetOrigin) {
|
||||
this.log.error(
|
||||
`message declined. origin was "${event.origin}" but expected "${String(this.targetOrigin)}"`,
|
||||
event.data
|
||||
)
|
||||
return
|
||||
}
|
||||
Optional.ofNullable(event.data)
|
||||
|
|
Loading…
Reference in a new issue