Revert "fix: replace class BaseUrlFromEnvExtractor"

This reverts commit 59bca4a81f.

Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
Tilman Vatteroth 2023-09-03 22:09:21 +02:00
parent 21ef5a0899
commit 7f5fd18e38
6 changed files with 105 additions and 95 deletions

View file

@ -5,8 +5,8 @@
*/ */
import { getNote } from '../../../api/notes' import { getNote } from '../../../api/notes'
import { redirect } from 'next/navigation' import { redirect } from 'next/navigation'
import { baseUrlFromEnvExtractor } from '../../../utils/base-url-from-env-extractor'
import { notFound } from 'next/navigation' import { notFound } from 'next/navigation'
import { extractBaseUrls } from '../../../utils/base-url-from-env-extractor'
interface PageProps { interface PageProps {
params: { id: string | undefined } params: { id: string | undefined }
@ -16,7 +16,7 @@ interface PageProps {
* Redirects the user to the editor if the link is a root level direct link to a version 1 note. * Redirects the user to the editor if the link is a root level direct link to a version 1 note.
*/ */
const DirectLinkFallback = async ({ params }: PageProps) => { const DirectLinkFallback = async ({ params }: PageProps) => {
const baseUrl = extractBaseUrls().editor const baseUrl = baseUrlFromEnvExtractor.extractBaseUrls().editor
if (params.id === undefined) { if (params.id === undefined) {
notFound() notFound()

View file

@ -11,7 +11,7 @@ import { MotdModal } from '../../components/global-dialogs/motd-modal/motd-modal
import { DarkMode } from '../../components/layout/dark-mode/dark-mode' import { DarkMode } from '../../components/layout/dark-mode/dark-mode'
import { UiNotificationBoundary } from '../../components/notifications/ui-notification-boundary' import { UiNotificationBoundary } from '../../components/notifications/ui-notification-boundary'
import { StoreProvider } from '../../redux/store-provider' import { StoreProvider } from '../../redux/store-provider'
import { extractBaseUrls } 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 type { Metadata } from 'next' import type { Metadata } from 'next'
import React from 'react' import React from 'react'
@ -20,7 +20,7 @@ import { getConfig } from '../../api/config'
configureLuxon() configureLuxon()
export default async function RootLayout({ children }: { children: React.ReactNode }) { export default async function RootLayout({ children }: { children: React.ReactNode }) {
const baseUrls = extractBaseUrls() const baseUrls = baseUrlFromEnvExtractor.extractBaseUrls()
const frontendConfig = await getConfig(baseUrls.editor) const frontendConfig = await getConfig(baseUrls.editor)
return ( return (

View file

@ -8,12 +8,12 @@ import { ApplicationLoader } from '../../components/application-loader/applicati
import { BaseUrlContextProvider } from '../../components/common/base-url/base-url-context-provider' import { BaseUrlContextProvider } from '../../components/common/base-url/base-url-context-provider'
import { FrontendConfigContextProvider } from '../../components/common/frontend-config-context/frontend-config-context-provider' import { FrontendConfigContextProvider } from '../../components/common/frontend-config-context/frontend-config-context-provider'
import { StoreProvider } from '../../redux/store-provider' import { StoreProvider } from '../../redux/store-provider'
import { extractBaseUrls } from '../../utils/base-url-from-env-extractor' import { baseUrlFromEnvExtractor } from '../../utils/base-url-from-env-extractor'
import React from 'react' import React from 'react'
import { getConfig } from '../../api/config' import { getConfig } from '../../api/config'
export default async function RootLayout({ children }: { children: React.ReactNode }) { export default async function RootLayout({ children }: { children: React.ReactNode }) {
const baseUrls = extractBaseUrls() const baseUrls = baseUrlFromEnvExtractor.extractBaseUrls()
const frontendConfig = await getConfig(baseUrls.renderer) const frontendConfig = await getConfig(baseUrls.renderer)
return ( return (

View file

@ -6,7 +6,7 @@
import { NextResponse } from 'next/server' import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server' import type { NextRequest } from 'next/server'
import { extractBaseUrls } from './utils/base-url-from-env-extractor' import { baseUrlFromEnvExtractor } from './utils/base-url-from-env-extractor'
/** /**
* Next.js middleware that checks if the expected and the current origin align. * Next.js middleware that checks if the expected and the current origin align.
@ -51,5 +51,9 @@ const determineOriginFromHeaders = (headers: Headers): string | undefined => {
* @param request The current request * @param request The current request
*/ */
const determineExpectedOrigin = (request: NextRequest): string => { const determineExpectedOrigin = (request: NextRequest): string => {
return new URL(request.nextUrl.pathname === '/render' ? extractBaseUrls().renderer : extractBaseUrls().editor).origin return new URL(
request.nextUrl.pathname === '/render'
? baseUrlFromEnvExtractor.extractBaseUrls().renderer
: baseUrlFromEnvExtractor.extractBaseUrls().editor
).origin
} }

View file

@ -3,22 +3,15 @@
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
import { BaseUrlFromEnvExtractor } from './base-url-from-env-extractor'
import type { BaseUrls } from '../components/common/base-url/base-url-context-provider'
describe('BaseUrlFromEnvExtractor', () => { describe('BaseUrlFromEnvExtractor', () => {
let extractBaseUrls: () => BaseUrls
beforeEach(async () => {
jest.resetModules()
extractBaseUrls = (await import('./base-url-from-env-extractor')).extractBaseUrls
})
it('should return the base urls if both are valid urls', () => { it('should return the base urls if both are valid urls', () => {
process.env.HD_BASE_URL = 'https://editor.example.org/' process.env.HD_BASE_URL = 'https://editor.example.org/'
process.env.HD_RENDERER_BASE_URL = 'https://renderer.example.org/' process.env.HD_RENDERER_BASE_URL = 'https://renderer.example.org/'
const sut = new BaseUrlFromEnvExtractor()
expect(extractBaseUrls()).toStrictEqual({ expect(sut.extractBaseUrls()).toStrictEqual({
renderer: 'https://renderer.example.org/', renderer: 'https://renderer.example.org/',
editor: 'https://editor.example.org/' editor: 'https://editor.example.org/'
}) })
@ -27,29 +20,33 @@ describe('BaseUrlFromEnvExtractor', () => {
it('should return an empty optional if no var is set', () => { it('should return an empty optional if no var is set', () => {
process.env.HD_BASE_URL = undefined process.env.HD_BASE_URL = undefined
process.env.HD_RENDERER_BASE_URL = undefined process.env.HD_RENDERER_BASE_URL = undefined
const sut = new BaseUrlFromEnvExtractor()
expect(() => extractBaseUrls()).toThrow() expect(() => sut.extractBaseUrls()).toThrow()
}) })
it("should return an empty optional if editor base url isn't an URL", () => { it("should return an empty optional if editor base url isn't an URL", () => {
process.env.HD_BASE_URL = 'bibedibabedibu' process.env.HD_BASE_URL = 'bibedibabedibu'
process.env.HD_RENDERER_BASE_URL = 'https://renderer.example.org/' process.env.HD_RENDERER_BASE_URL = 'https://renderer.example.org/'
const sut = new BaseUrlFromEnvExtractor()
expect(() => extractBaseUrls()).toThrow() expect(() => sut.extractBaseUrls()).toThrow()
}) })
it("should return an empty optional if renderer base url isn't an URL", () => { it("should return an empty optional if renderer base url isn't an URL", () => {
process.env.HD_BASE_URL = 'https://editor.example.org/' process.env.HD_BASE_URL = 'https://editor.example.org/'
process.env.HD_RENDERER_BASE_URL = 'bibedibabedibu' process.env.HD_RENDERER_BASE_URL = 'bibedibabedibu'
const sut = new BaseUrlFromEnvExtractor()
expect(() => extractBaseUrls()).toThrow() expect(() => sut.extractBaseUrls()).toThrow()
}) })
it("should return an optional if editor base url isn't ending with a slash", () => { it("should return an optional if editor base url isn't ending with a slash", () => {
process.env.HD_BASE_URL = 'https://editor.example.org' process.env.HD_BASE_URL = 'https://editor.example.org'
process.env.HD_RENDERER_BASE_URL = 'https://renderer.example.org/' process.env.HD_RENDERER_BASE_URL = 'https://renderer.example.org/'
const sut = new BaseUrlFromEnvExtractor()
expect(extractBaseUrls()).toStrictEqual({ expect(sut.extractBaseUrls()).toStrictEqual({
renderer: 'https://renderer.example.org/', renderer: 'https://renderer.example.org/',
editor: 'https://editor.example.org/' editor: 'https://editor.example.org/'
}) })
@ -58,8 +55,9 @@ describe('BaseUrlFromEnvExtractor', () => {
it("should return an optional if renderer base url isn't ending with a slash", () => { it("should return an optional if renderer base url isn't ending with a slash", () => {
process.env.HD_BASE_URL = 'https://editor.example.org/' process.env.HD_BASE_URL = 'https://editor.example.org/'
process.env.HD_RENDERER_BASE_URL = 'https://renderer.example.org' process.env.HD_RENDERER_BASE_URL = 'https://renderer.example.org'
const sut = new BaseUrlFromEnvExtractor()
expect(extractBaseUrls()).toStrictEqual({ expect(sut.extractBaseUrls()).toStrictEqual({
renderer: 'https://renderer.example.org/', renderer: 'https://renderer.example.org/',
editor: 'https://editor.example.org/' editor: 'https://editor.example.org/'
}) })
@ -68,8 +66,9 @@ describe('BaseUrlFromEnvExtractor', () => {
it('should copy editor base url to renderer base url if renderer base url is omitted', () => { it('should copy editor base url to renderer base url if renderer base url is omitted', () => {
process.env.HD_BASE_URL = 'https://editor.example.org/' process.env.HD_BASE_URL = 'https://editor.example.org/'
delete process.env.HD_RENDERER_BASE_URL delete process.env.HD_RENDERER_BASE_URL
const sut = new BaseUrlFromEnvExtractor()
expect(extractBaseUrls()).toStrictEqual({ expect(sut.extractBaseUrls()).toStrictEqual({
renderer: 'https://editor.example.org/', renderer: 'https://editor.example.org/',
editor: 'https://editor.example.org/' editor: 'https://editor.example.org/'
}) })

View file

@ -9,81 +9,88 @@ import { isTestMode, isBuildTime } from './test-modes'
import { NoSubdirectoryAllowedError, parseUrl } from '@hedgedoc/commons' import { NoSubdirectoryAllowedError, parseUrl } from '@hedgedoc/commons'
import { Optional } from '@mrdrogdrog/optional' import { Optional } from '@mrdrogdrog/optional'
let baseUrls: BaseUrls | undefined = undefined
const logger = new Logger('Base URL Configuration')
function extractUrlFromEnvVar(envVarName: string, envVarValue: string | undefined): Optional<URL> {
try {
return parseUrl(envVarValue)
} catch (error) {
if (error instanceof NoSubdirectoryAllowedError) {
logger.error(error.message)
return Optional.empty()
} else {
throw error
}
}
}
function extractEditorBaseUrlFromEnv(): Optional<URL> {
const envValue = extractUrlFromEnvVar('HD_BASE_URL', process.env.HD_BASE_URL)
if (envValue.isEmpty()) {
logger.error("HD_BASE_URL isn't a valid URL!")
}
return envValue
}
function extractRendererBaseUrlFromEnv(editorBaseUrl: URL): Optional<URL> {
if (isTestMode) {
logger.info('Test mode activated. Using editor base url for renderer.')
return Optional.of(editorBaseUrl)
}
if (!process.env.HD_RENDERER_BASE_URL) {
logger.info('HD_RENDERER_BASE_URL is unset. Using editor base url for renderer.')
return Optional.of(editorBaseUrl)
}
return extractUrlFromEnvVar('HD_RENDERER_BASE_URL', process.env.HD_RENDERER_BASE_URL)
}
function renewBaseUrls(): BaseUrls {
return extractEditorBaseUrlFromEnv()
.flatMap((editorBaseUrl) =>
extractRendererBaseUrlFromEnv(editorBaseUrl).map((rendererBaseUrl) => {
return {
editor: editorBaseUrl.toString(),
renderer: rendererBaseUrl.toString()
}
})
)
.orElseThrow(() => new Error('couldnt parse env vars'))
}
function logBaseUrls() {
if (baseUrls === undefined) {
return
}
logger.info('Editor base URL', baseUrls.editor.toString())
logger.info('Renderer base URL', baseUrls.renderer.toString())
}
/** /**
* Extracts the editor and renderer base urls from the environment variables. * Extracts and caches the editor and renderer base urls from the environment variables.
*
* @return An {@link Optional} with the base urls.
*/ */
export function extractBaseUrls(): BaseUrls { export class BaseUrlFromEnvExtractor {
if (isBuildTime) { private baseUrls: BaseUrls | undefined
return { private readonly logger = new Logger('Base URL Configuration')
editor: 'https://example.org/',
renderer: 'https://example.org/' private extractUrlFromEnvVar(envVarName: string, envVarValue: string | undefined): Optional<URL> {
try {
return parseUrl(envVarValue)
} catch (error) {
if (error instanceof NoSubdirectoryAllowedError) {
this.logger.error(error.message)
return Optional.empty()
} else {
throw error
}
} }
} }
if (baseUrls === undefined) { private extractEditorBaseUrlFromEnv(): Optional<URL> {
baseUrls = renewBaseUrls() const envValue = this.extractUrlFromEnvVar('HD_BASE_URL', process.env.HD_BASE_URL)
logBaseUrls() if (envValue.isEmpty()) {
this.logger.error("HD_BASE_URL isn't a valid URL!")
}
return envValue
}
private extractRendererBaseUrlFromEnv(editorBaseUrl: URL): Optional<URL> {
if (isTestMode) {
this.logger.info('Test mode activated. Using editor base url for renderer.')
return Optional.of(editorBaseUrl)
}
if (!process.env.HD_RENDERER_BASE_URL) {
this.logger.info('HD_RENDERER_BASE_URL is unset. Using editor base url for renderer.')
return Optional.of(editorBaseUrl)
}
return this.extractUrlFromEnvVar('HD_RENDERER_BASE_URL', process.env.HD_RENDERER_BASE_URL)
}
private renewBaseUrls(): BaseUrls {
return this.extractEditorBaseUrlFromEnv()
.flatMap((editorBaseUrl) =>
this.extractRendererBaseUrlFromEnv(editorBaseUrl).map((rendererBaseUrl) => {
return {
editor: editorBaseUrl.toString(),
renderer: rendererBaseUrl.toString()
}
})
)
.orElseThrow(() => new Error('couldnt parse env vars'))
}
/**
* Extracts the editor and renderer base urls from the environment variables.
*
* @return An {@link Optional} with the base urls.
*/
public extractBaseUrls(): BaseUrls {
if (isBuildTime) {
return {
editor: 'https://example.org/',
renderer: 'https://example.org/'
}
}
if (this.baseUrls === undefined) {
this.baseUrls = this.renewBaseUrls()
this.logBaseUrls()
}
return this.baseUrls
}
private logBaseUrls() {
if (this.baseUrls === undefined) {
return
}
this.logger.info('Editor base URL', this.baseUrls.editor.toString())
this.logger.info('Renderer base URL', this.baseUrls.renderer.toString())
} }
return baseUrls
} }
export const baseUrlFromEnvExtractor = new BaseUrlFromEnvExtractor()