mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-12 22:26:08 -04:00
fix(config): Replace HD_DOMAIN and HD_EDITOR_BASE_URL with HD_BASE_URL
Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
parent
65ac00913b
commit
5e1fdbe81d
21 changed files with 255 additions and 92 deletions
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
HD_DOMAIN="http://localhost"
|
||||
HD_BASE_URL="http://localhost/"
|
||||
HD_MEDIA_BACKEND="filesystem"
|
||||
HD_MEDIA_BACKEND_FILESYSTEM_UPLOAD_PATH="uploads/"
|
||||
HD_DATABASE_TYPE="sqlite"
|
||||
|
|
|
@ -21,7 +21,7 @@ To build a production image, run the following command *from the root of the rep
|
|||
When you run the image, you need to provide environment variables to configure HedgeDoc.
|
||||
See [the config docs](../../docs/content/config/index.md) for more information.
|
||||
This example starts HedgeDoc on localhost, with non-persistent storage:
|
||||
`docker run -e HD_DOMAIN=http://localhost -e HD_MEDIA_BACKEND=filesystem -e HD_MEDIA_BACKEND_FILESYSTEM_UPLOAD_PATH=uploads -e HD_DATABASE_TYPE=sqlite -e HD_DATABASE_NAME=hedgedoc.sqlite -e HD_SESSION_SECRET=foobar -e HD_LOGLEVEL=debug -p 3000:3000 hedgedoc-prod`
|
||||
`docker run -e HD_BASE_URL=http://localhost -e HD_MEDIA_BACKEND=filesystem -e HD_MEDIA_BACKEND_FILESYSTEM_UPLOAD_PATH=uploads -e HD_DATABASE_TYPE=sqlite -e HD_DATABASE_NAME=hedgedoc.sqlite -e HD_SESSION_SECRET=foobar -e HD_LOGLEVEL=debug -p 3000:3000 hedgedoc-prod`
|
||||
|
||||
|
||||
## Build a development image
|
||||
|
|
|
@ -9,9 +9,9 @@ import appConfig from './app.config';
|
|||
import { Loglevel } from './loglevel.enum';
|
||||
|
||||
describe('appConfig', () => {
|
||||
const domain = 'https://example.com';
|
||||
const invalidDomain = 'localhost';
|
||||
const rendererBaseUrl = 'https://render.example.com';
|
||||
const baseUrl = 'https://example.com/';
|
||||
const invalidBaseUrl = 'localhost';
|
||||
const rendererBaseUrl = 'https://render.example.com/';
|
||||
const port = 3333;
|
||||
const negativePort = -9000;
|
||||
const floatPort = 3.14;
|
||||
|
@ -26,7 +26,7 @@ describe('appConfig', () => {
|
|||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_DOMAIN: domain,
|
||||
HD_BASE_URL: baseUrl,
|
||||
HD_RENDERER_BASE_URL: rendererBaseUrl,
|
||||
PORT: port.toString(),
|
||||
HD_LOGLEVEL: loglevel,
|
||||
|
@ -38,7 +38,7 @@ describe('appConfig', () => {
|
|||
},
|
||||
);
|
||||
const config = appConfig();
|
||||
expect(config.domain).toEqual(domain);
|
||||
expect(config.baseUrl).toEqual(baseUrl);
|
||||
expect(config.rendererBaseUrl).toEqual(rendererBaseUrl);
|
||||
expect(config.port).toEqual(port);
|
||||
expect(config.loglevel).toEqual(loglevel);
|
||||
|
@ -50,7 +50,7 @@ describe('appConfig', () => {
|
|||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_DOMAIN: domain,
|
||||
HD_BASE_URL: baseUrl,
|
||||
PORT: port.toString(),
|
||||
HD_LOGLEVEL: loglevel,
|
||||
HD_PERSIST_INTERVAL: '100',
|
||||
|
@ -61,8 +61,8 @@ describe('appConfig', () => {
|
|||
},
|
||||
);
|
||||
const config = appConfig();
|
||||
expect(config.domain).toEqual(domain);
|
||||
expect(config.rendererBaseUrl).toEqual(domain);
|
||||
expect(config.baseUrl).toEqual(baseUrl);
|
||||
expect(config.rendererBaseUrl).toEqual(baseUrl);
|
||||
expect(config.port).toEqual(port);
|
||||
expect(config.loglevel).toEqual(loglevel);
|
||||
expect(config.persistInterval).toEqual(100);
|
||||
|
@ -73,7 +73,7 @@ describe('appConfig', () => {
|
|||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_DOMAIN: domain,
|
||||
HD_BASE_URL: baseUrl,
|
||||
HD_RENDERER_BASE_URL: rendererBaseUrl,
|
||||
HD_LOGLEVEL: loglevel,
|
||||
HD_PERSIST_INTERVAL: '100',
|
||||
|
@ -84,7 +84,7 @@ describe('appConfig', () => {
|
|||
},
|
||||
);
|
||||
const config = appConfig();
|
||||
expect(config.domain).toEqual(domain);
|
||||
expect(config.baseUrl).toEqual(baseUrl);
|
||||
expect(config.rendererBaseUrl).toEqual(rendererBaseUrl);
|
||||
expect(config.port).toEqual(3000);
|
||||
expect(config.loglevel).toEqual(loglevel);
|
||||
|
@ -96,7 +96,7 @@ describe('appConfig', () => {
|
|||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_DOMAIN: domain,
|
||||
HD_BASE_URL: baseUrl,
|
||||
HD_RENDERER_BASE_URL: rendererBaseUrl,
|
||||
PORT: port.toString(),
|
||||
HD_PERSIST_INTERVAL: '100',
|
||||
|
@ -107,7 +107,7 @@ describe('appConfig', () => {
|
|||
},
|
||||
);
|
||||
const config = appConfig();
|
||||
expect(config.domain).toEqual(domain);
|
||||
expect(config.baseUrl).toEqual(baseUrl);
|
||||
expect(config.rendererBaseUrl).toEqual(rendererBaseUrl);
|
||||
expect(config.port).toEqual(port);
|
||||
expect(config.loglevel).toEqual(Loglevel.WARN);
|
||||
|
@ -119,7 +119,7 @@ describe('appConfig', () => {
|
|||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_DOMAIN: domain,
|
||||
HD_BASE_URL: baseUrl,
|
||||
HD_RENDERER_BASE_URL: rendererBaseUrl,
|
||||
HD_LOGLEVEL: loglevel,
|
||||
PORT: port.toString(),
|
||||
|
@ -130,7 +130,7 @@ describe('appConfig', () => {
|
|||
},
|
||||
);
|
||||
const config = appConfig();
|
||||
expect(config.domain).toEqual(domain);
|
||||
expect(config.baseUrl).toEqual(baseUrl);
|
||||
expect(config.rendererBaseUrl).toEqual(rendererBaseUrl);
|
||||
expect(config.port).toEqual(port);
|
||||
expect(config.loglevel).toEqual(Loglevel.TRACE);
|
||||
|
@ -142,7 +142,7 @@ describe('appConfig', () => {
|
|||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_DOMAIN: domain,
|
||||
HD_BASE_URL: baseUrl,
|
||||
HD_RENDERER_BASE_URL: rendererBaseUrl,
|
||||
HD_LOGLEVEL: loglevel,
|
||||
PORT: port.toString(),
|
||||
|
@ -154,7 +154,7 @@ describe('appConfig', () => {
|
|||
},
|
||||
);
|
||||
const config = appConfig();
|
||||
expect(config.domain).toEqual(domain);
|
||||
expect(config.baseUrl).toEqual(baseUrl);
|
||||
expect(config.rendererBaseUrl).toEqual(rendererBaseUrl);
|
||||
expect(config.port).toEqual(port);
|
||||
expect(config.loglevel).toEqual(Loglevel.TRACE);
|
||||
|
@ -163,11 +163,11 @@ describe('appConfig', () => {
|
|||
});
|
||||
});
|
||||
describe('throws error', () => {
|
||||
it('when given a non-valid HD_DOMAIN', async () => {
|
||||
it('when given a non-valid HD_BASE_URL', async () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_DOMAIN: invalidDomain,
|
||||
HD_BASE_URL: invalidBaseUrl,
|
||||
PORT: port.toString(),
|
||||
HD_LOGLEVEL: loglevel,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
|
@ -176,7 +176,25 @@ describe('appConfig', () => {
|
|||
clear: true,
|
||||
},
|
||||
);
|
||||
expect(() => appConfig()).toThrow('HD_DOMAIN');
|
||||
expect(() => appConfig()).toThrow('HD_BASE_URL');
|
||||
restore();
|
||||
});
|
||||
|
||||
it('when given a base url with path but no trailing slash in HD_BASE_URL', async () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_BASE_URL: 'https://example.org/a',
|
||||
HD_LOGLEVEL: loglevel,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
},
|
||||
);
|
||||
expect(() => appConfig()).toThrow(
|
||||
'"HD_BASE_URL" must end with a trailing slash',
|
||||
);
|
||||
restore();
|
||||
});
|
||||
|
||||
|
@ -184,7 +202,7 @@ describe('appConfig', () => {
|
|||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_DOMAIN: domain,
|
||||
HD_BASE_URL: baseUrl,
|
||||
PORT: negativePort.toString(),
|
||||
HD_LOGLEVEL: loglevel,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
|
@ -201,7 +219,7 @@ describe('appConfig', () => {
|
|||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_DOMAIN: domain,
|
||||
HD_BASE_URL: baseUrl,
|
||||
PORT: outOfRangePort.toString(),
|
||||
HD_LOGLEVEL: loglevel,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
|
@ -220,7 +238,7 @@ describe('appConfig', () => {
|
|||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_DOMAIN: domain,
|
||||
HD_BASE_URL: baseUrl,
|
||||
PORT: floatPort.toString(),
|
||||
HD_LOGLEVEL: loglevel,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
|
@ -237,7 +255,7 @@ describe('appConfig', () => {
|
|||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_DOMAIN: domain,
|
||||
HD_BASE_URL: baseUrl,
|
||||
PORT: invalidPort,
|
||||
HD_LOGLEVEL: loglevel,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
|
@ -254,7 +272,7 @@ describe('appConfig', () => {
|
|||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_DOMAIN: domain,
|
||||
HD_BASE_URL: baseUrl,
|
||||
PORT: port.toString(),
|
||||
HD_LOGLEVEL: invalidLoglevel,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
|
@ -271,7 +289,7 @@ describe('appConfig', () => {
|
|||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_DOMAIN: domain,
|
||||
HD_BASE_URL: baseUrl,
|
||||
PORT: port.toString(),
|
||||
HD_LOGLEVEL: invalidLoglevel,
|
||||
HD_PERSIST_INTERVAL: invalidPersistInterval.toString(),
|
||||
|
|
|
@ -3,31 +3,50 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import {
|
||||
MissingTrailingSlashError,
|
||||
parseUrl,
|
||||
WrongProtocolError,
|
||||
} from '@hedgedoc/commons';
|
||||
import { registerAs } from '@nestjs/config';
|
||||
import * as Joi from 'joi';
|
||||
import { CustomHelpers, ErrorReport } from 'joi';
|
||||
|
||||
import { Loglevel } from './loglevel.enum';
|
||||
import { buildErrorMessage, parseOptionalNumber } from './utils';
|
||||
|
||||
export interface AppConfig {
|
||||
domain: string;
|
||||
baseUrl: string;
|
||||
rendererBaseUrl: string;
|
||||
port: number;
|
||||
loglevel: Loglevel;
|
||||
persistInterval: number;
|
||||
}
|
||||
|
||||
function validateUrlWithTrailingSlash(
|
||||
value: string,
|
||||
helpers: CustomHelpers,
|
||||
): string | ErrorReport {
|
||||
try {
|
||||
return parseUrl(value).isPresent() ? value : helpers.error('string.uri');
|
||||
} catch (error) {
|
||||
if (error instanceof MissingTrailingSlashError) {
|
||||
return helpers.error('url.missingTrailingSlash');
|
||||
} else if (error instanceof WrongProtocolError) {
|
||||
return helpers.error('url.wrongProtocol');
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const schema = Joi.object({
|
||||
domain: Joi.string()
|
||||
.uri({
|
||||
scheme: /https?/,
|
||||
})
|
||||
.label('HD_DOMAIN'),
|
||||
baseUrl: Joi.string()
|
||||
.custom(validateUrlWithTrailingSlash)
|
||||
.label('HD_BASE_URL'),
|
||||
rendererBaseUrl: Joi.string()
|
||||
.uri({
|
||||
scheme: /https?/,
|
||||
})
|
||||
.default(Joi.ref('domain'))
|
||||
.custom(validateUrlWithTrailingSlash)
|
||||
.default(Joi.ref('baseUrl'))
|
||||
.optional()
|
||||
.label('HD_RENDERER_BASE_URL'),
|
||||
port: Joi.number()
|
||||
|
@ -48,12 +67,17 @@ const schema = Joi.object({
|
|||
.default(10)
|
||||
.optional()
|
||||
.label('HD_PERSIST_INTERVAL'),
|
||||
}).messages({
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
'url.missingTrailingSlash': '{{#label}} must end with a trailing slash',
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
'url.wrongProtocol': '{{#label}} protocol must be HTTP or HTTPS',
|
||||
});
|
||||
|
||||
export default registerAs('appConfig', () => {
|
||||
const appConfig = schema.validate(
|
||||
{
|
||||
domain: process.env.HD_DOMAIN,
|
||||
baseUrl: process.env.HD_BASE_URL,
|
||||
rendererBaseUrl: process.env.HD_RENDERER_BASE_URL,
|
||||
port: parseOptionalNumber(process.env.PORT),
|
||||
loglevel: process.env.HD_LOGLEVEL,
|
||||
|
|
|
@ -11,7 +11,7 @@ import { Loglevel } from '../loglevel.enum';
|
|||
|
||||
export function createDefaultMockAppConfig(): AppConfig {
|
||||
return {
|
||||
domain: 'md.example.com',
|
||||
baseUrl: 'md.example.com',
|
||||
rendererBaseUrl: 'md-renderer.example.com',
|
||||
port: 3000,
|
||||
loglevel: Loglevel.ERROR,
|
||||
|
|
|
@ -167,7 +167,7 @@ describe('FrontendConfigService', () => {
|
|||
]) {
|
||||
it(`works with ${JSON.stringify(authConfigConfigured)}`, async () => {
|
||||
const appConfig: AppConfig = {
|
||||
domain: domain,
|
||||
baseUrl: domain,
|
||||
rendererBaseUrl: 'https://renderer.example.org',
|
||||
port: 3000,
|
||||
loglevel: Loglevel.ERROR,
|
||||
|
@ -325,7 +325,7 @@ describe('FrontendConfigService', () => {
|
|||
]) {
|
||||
it(`combination #${index} works`, async () => {
|
||||
const appConfig: AppConfig = {
|
||||
domain: domain,
|
||||
baseUrl: domain,
|
||||
rendererBaseUrl: 'https://renderer.example.org',
|
||||
port: 3000,
|
||||
loglevel: Loglevel.ERROR,
|
||||
|
|
|
@ -18,7 +18,7 @@ describe('App', () => {
|
|||
})
|
||||
.overrideProvider(getConfigToken('appConfig'))
|
||||
.useValue({
|
||||
domain: 'localhost',
|
||||
baseUrl: 'localhost',
|
||||
port: 3333,
|
||||
})
|
||||
.overrideProvider(getConfigToken('mediaConfig'))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue