mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2024-11-23 10:16:32 -05:00
Merge pull request #733 from hedgedoc/config/split
This commit is contained in:
commit
9b552a6ead
20 changed files with 289 additions and 273 deletions
|
@ -8,6 +8,7 @@ import { ConfigModule } from '@nestjs/config';
|
|||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||
import appConfigMock from '../../../config/app.config.mock';
|
||||
import mediaConfigMock from '../../../config/media.config.mock';
|
||||
import { LoggerModule } from '../../../logger/logger.module';
|
||||
import { MediaUpload } from '../../../media/media-upload.entity';
|
||||
import { MediaModule } from '../../../media/media.module';
|
||||
|
@ -31,7 +32,7 @@ describe('Media Controller', () => {
|
|||
imports: [
|
||||
ConfigModule.forRoot({
|
||||
isGlobal: true,
|
||||
load: [appConfigMock],
|
||||
load: [appConfigMock, mediaConfigMock],
|
||||
}),
|
||||
LoggerModule,
|
||||
MediaModule,
|
||||
|
|
|
@ -19,6 +19,11 @@ import { PermissionsModule } from './permissions/permissions.module';
|
|||
import { RevisionsModule } from './revisions/revisions.module';
|
||||
import { UsersModule } from './users/users.module';
|
||||
import appConfig from './config/app.config';
|
||||
import mediaConfig from './config/media.config';
|
||||
import hstsConfig from './config/hsts.config';
|
||||
import cspConfig from './config/csp.config';
|
||||
import databaseConfig from './config/database.config';
|
||||
import authConfig from './config/auth.config';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
|
@ -29,7 +34,14 @@ import appConfig from './config/app.config';
|
|||
synchronize: true,
|
||||
}),
|
||||
ConfigModule.forRoot({
|
||||
load: [appConfig],
|
||||
load: [
|
||||
appConfig,
|
||||
mediaConfig,
|
||||
hstsConfig,
|
||||
cspConfig,
|
||||
databaseConfig,
|
||||
authConfig,
|
||||
],
|
||||
isGlobal: true,
|
||||
}),
|
||||
NotesModule,
|
||||
|
|
|
@ -8,12 +8,4 @@ import { registerAs } from '@nestjs/config';
|
|||
|
||||
export default registerAs('appConfig', () => ({
|
||||
port: 3000,
|
||||
media: {
|
||||
backend: {
|
||||
use: 'filesystem',
|
||||
filesystem: {
|
||||
uploadPath: 'uploads',
|
||||
},
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
|
|
@ -7,46 +7,11 @@
|
|||
import { registerAs } from '@nestjs/config';
|
||||
import * as Joi from 'joi';
|
||||
import { Loglevel } from './loglevel.enum';
|
||||
import { appConfigHsts, HstsConfig, hstsSchema } from './hsts-config';
|
||||
import { appConfigCsp, CspConfig, cspSchema } from './csp-config';
|
||||
import { appConfigMedia, MediaConfig, mediaSchema } from './media-config';
|
||||
import {
|
||||
appConfigDatabase,
|
||||
DatabaseConfig,
|
||||
databaseSchema,
|
||||
} from './database-config';
|
||||
import { appConfigAuth, AuthConfig, authSchema } from './auth-config';
|
||||
|
||||
// import { LinkifyHeaderStyle } from './linkify-header-style';
|
||||
|
||||
export interface AppConfig {
|
||||
domain: string;
|
||||
port: number;
|
||||
loglevel: Loglevel;
|
||||
/*linkifyHeaderStyle: LinkifyHeaderStyle;
|
||||
sourceURL: string;
|
||||
urlPath: string;
|
||||
host: string;
|
||||
path: string;
|
||||
urlAddPort: boolean;
|
||||
cookiePolicy: string;
|
||||
protocolUseSSL: boolean;
|
||||
allowOrigin: string[];
|
||||
useCDN: boolean;
|
||||
enableAnonymous: boolean;
|
||||
enableAnonymousEdits: boolean;
|
||||
enableFreeURL: boolean;
|
||||
forbiddenNoteIDs: string[];
|
||||
defaultPermission: string;
|
||||
sessionSecret: string;
|
||||
sessionLife: number;
|
||||
tooBusyLag: number;
|
||||
enableGravatar: boolean;*/
|
||||
hsts: HstsConfig;
|
||||
csp: CspConfig;
|
||||
media: MediaConfig;
|
||||
database: DatabaseConfig;
|
||||
auth: AuthConfig;
|
||||
}
|
||||
|
||||
const schema = Joi.object({
|
||||
|
@ -56,30 +21,6 @@ const schema = Joi.object({
|
|||
.valid(...Object.values(Loglevel))
|
||||
.default(Loglevel.WARN)
|
||||
.optional(),
|
||||
/*linkifyHeaderStyle: Joi.string().valid(...Object.values(LinkifyHeaderStyle)).default(LinkifyHeaderStyle.GFM).optional(),
|
||||
sourceURL: Joi.string(),
|
||||
urlPath: Joi.string(),
|
||||
host: Joi.string().default('::').optional(),
|
||||
path: Joi.string(),
|
||||
urlAddPort: Joi.boolean().default(false).optional(),
|
||||
cookiePolicy: Joi.string(),
|
||||
protocolUseSSL: Joi.boolean().default(true).optional(),
|
||||
allowOrigin: Joi.array().items(Joi.string()),
|
||||
useCDN: Joi.boolean().default(false).optional(),
|
||||
enableAnonymous: Joi.boolean().default(true).optional(),
|
||||
enableAnonymousEdits: Joi.boolean().default(false).optional(),
|
||||
enableFreeURL: Joi.boolean().default(false).optional(),
|
||||
forbiddenNoteIDs: Joi.array().items(Joi.string()),
|
||||
defaultPermission: Joi.string(),
|
||||
sessionSecret: Joi.string(),
|
||||
sessionLife: Joi.number().default(14 * 24 * 60 * 60 * 1000).optional(),
|
||||
tooBusyLag: Joi.number().default(70).optional(),
|
||||
enableGravatar: Joi.boolean().default(true).optional(),*/
|
||||
hsts: hstsSchema,
|
||||
csp: cspSchema,
|
||||
media: mediaSchema,
|
||||
database: databaseSchema,
|
||||
auth: authSchema,
|
||||
});
|
||||
|
||||
export default registerAs('appConfig', async () => {
|
||||
|
@ -87,31 +28,7 @@ export default registerAs('appConfig', async () => {
|
|||
{
|
||||
domain: process.env.HD_DOMAIN,
|
||||
port: parseInt(process.env.PORT) || undefined,
|
||||
loglevel: process.env.HD_LOGLEVEL, //|| Loglevel.WARN,
|
||||
/*linkifyHeaderStyle: process.env.HD_LINKIFY_HEADER_STYLE,
|
||||
sourceURL: process.env.HD_SOURCE_URL,
|
||||
urlPath: process.env.HD_URL_PATH,
|
||||
host: process.env.HD_HOST || '::',
|
||||
path: process.env.HD_PATH,
|
||||
urlAddPort: process.env.HD_URL_ADDPORT,
|
||||
cookiePolicy: process.env.HD_COOKIE_POLICY,
|
||||
protocolUseSSL: process.env.HD_PROTOCOL_USESSL || true,
|
||||
allowOrigin: toArrayConfig(process.env.HD_ALLOW_ORIGIN),
|
||||
useCDN: process.env.HD_USECDN,
|
||||
enableAnonymous: process.env.HD_ENABLE_ANONYMOUS || true,
|
||||
enableAnonymousEdits: process.env.HD_ENABLE_ANONYMOUS_EDITS,
|
||||
enableFreeURL: process.env.HD_ENABLE_FREEURL,
|
||||
forbiddenNoteIDs: toArrayConfig(process.env.HD_FORBIDDEN_NOTE_IDS),
|
||||
defaultPermission: process.env.HD_DEFAULT_PERMISSION,
|
||||
sessionSecret: process.env.HD_SESSION_SECRET,
|
||||
sessionLife: parseInt(process.env.HD_SESSION_LIFE) || 14 * 24 * 60 * 60 * 1000,
|
||||
tooBusyLag: parseInt(process.env.HD_TOOBUSY_LAG) || 70,
|
||||
enableGravatar: process.env.HD_ENABLE_GRAVATAR || true,*/
|
||||
hsts: appConfigHsts,
|
||||
csp: appConfigCsp,
|
||||
media: appConfigMedia,
|
||||
database: appConfigDatabase,
|
||||
auth: appConfigAuth,
|
||||
loglevel: process.env.HD_LOGLEVEL,
|
||||
},
|
||||
{
|
||||
abortEarly: false,
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
import * as Joi from 'joi';
|
||||
import { GitlabScope, GitlabVersion } from './gitlab.enum';
|
||||
import { toArrayConfig } from './utils';
|
||||
import { registerAs } from '@nestjs/config';
|
||||
|
||||
export interface AuthConfig {
|
||||
email: {
|
||||
|
@ -99,7 +100,7 @@ export interface AuthConfig {
|
|||
];
|
||||
}
|
||||
|
||||
export const authSchema = Joi.object({
|
||||
const authSchema = Joi.object({
|
||||
email: {
|
||||
enableLogin: Joi.boolean().default(false).optional(),
|
||||
enableRegister: Joi.boolean().default(false).optional(),
|
||||
|
@ -297,35 +298,47 @@ const oauth2s = oauth2Names.map((oauth2Name) => {
|
|||
};
|
||||
});
|
||||
|
||||
export const appConfigAuth = {
|
||||
email: {
|
||||
enableLogin: process.env.HD_AUTH_EMAIL_ENABLE_LOGIN,
|
||||
enableRegister: process.env.HD_AUTH_EMAIL_ENABLE_REGISTER,
|
||||
},
|
||||
facebook: {
|
||||
clientID: process.env.HD_AUTH_FACEBOOK_CLIENT_ID,
|
||||
clientSecret: process.env.HD_AUTH_FACEBOOK_CLIENT_SECRET,
|
||||
},
|
||||
twitter: {
|
||||
consumerKey: process.env.HD_AUTH_TWITTER_CONSUMER_KEY,
|
||||
consumerSecret: process.env.HD_AUTH_TWITTER_CONSUMER_SECRET,
|
||||
},
|
||||
github: {
|
||||
clientID: process.env.HD_AUTH_GITHUB_CLIENT_ID,
|
||||
clientSecret: process.env.HD_AUTH_GITHUB_CLIENT_SECRET,
|
||||
},
|
||||
dropbox: {
|
||||
clientID: process.env.HD_AUTH_DROPBOX_CLIENT_ID,
|
||||
clientSecret: process.env.HD_AUTH_DROPBOX_CLIENT_SECRET,
|
||||
appKey: process.env.HD_AUTH_DROPBOX_APP_KEY,
|
||||
},
|
||||
google: {
|
||||
clientID: process.env.HD_AUTH_GOOGLE_CLIENT_ID,
|
||||
clientSecret: process.env.HD_AUTH_GOOGLE_CLIENT_SECRET,
|
||||
apiKey: process.env.HD_AUTH_GOOGLE_APP_KEY,
|
||||
},
|
||||
gitlab: gitlabs,
|
||||
ldap: ldaps,
|
||||
saml: samls,
|
||||
oauth2: oauth2s,
|
||||
};
|
||||
export default registerAs('authConfig', async () => {
|
||||
const authConfig = authSchema.validate(
|
||||
{
|
||||
email: {
|
||||
enableLogin: process.env.HD_AUTH_EMAIL_ENABLE_LOGIN,
|
||||
enableRegister: process.env.HD_AUTH_EMAIL_ENABLE_REGISTER,
|
||||
},
|
||||
facebook: {
|
||||
clientID: process.env.HD_AUTH_FACEBOOK_CLIENT_ID,
|
||||
clientSecret: process.env.HD_AUTH_FACEBOOK_CLIENT_SECRET,
|
||||
},
|
||||
twitter: {
|
||||
consumerKey: process.env.HD_AUTH_TWITTER_CONSUMER_KEY,
|
||||
consumerSecret: process.env.HD_AUTH_TWITTER_CONSUMER_SECRET,
|
||||
},
|
||||
github: {
|
||||
clientID: process.env.HD_AUTH_GITHUB_CLIENT_ID,
|
||||
clientSecret: process.env.HD_AUTH_GITHUB_CLIENT_SECRET,
|
||||
},
|
||||
dropbox: {
|
||||
clientID: process.env.HD_AUTH_DROPBOX_CLIENT_ID,
|
||||
clientSecret: process.env.HD_AUTH_DROPBOX_CLIENT_SECRET,
|
||||
appKey: process.env.HD_AUTH_DROPBOX_APP_KEY,
|
||||
},
|
||||
google: {
|
||||
clientID: process.env.HD_AUTH_GOOGLE_CLIENT_ID,
|
||||
clientSecret: process.env.HD_AUTH_GOOGLE_CLIENT_SECRET,
|
||||
apiKey: process.env.HD_AUTH_GOOGLE_APP_KEY,
|
||||
},
|
||||
gitlab: gitlabs,
|
||||
ldap: ldaps,
|
||||
saml: samls,
|
||||
oauth2: oauth2s,
|
||||
},
|
||||
{
|
||||
abortEarly: false,
|
||||
presence: 'required',
|
||||
},
|
||||
);
|
||||
if (authConfig.error) {
|
||||
throw new Error(authConfig.error.toString());
|
||||
}
|
||||
return authConfig.value;
|
||||
});
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import * as Joi from 'joi';
|
||||
|
||||
export interface CspConfig {
|
||||
enable: boolean;
|
||||
maxAgeSeconds: number;
|
||||
includeSubdomains: boolean;
|
||||
preload: boolean;
|
||||
}
|
||||
|
||||
export const cspSchema = Joi.object({
|
||||
enable: Joi.boolean().default(true).optional(),
|
||||
reportURI: Joi.string().optional(),
|
||||
});
|
||||
|
||||
export const appConfigCsp = {
|
||||
enable: process.env.HD_CSP_ENABLE || true,
|
||||
reportURI: process.env.HD_CSP_REPORTURI,
|
||||
};
|
37
src/config/csp.config.ts
Normal file
37
src/config/csp.config.ts
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import * as Joi from 'joi';
|
||||
import { registerAs } from '@nestjs/config';
|
||||
|
||||
export interface CspConfig {
|
||||
enable: boolean;
|
||||
maxAgeSeconds: number;
|
||||
includeSubdomains: boolean;
|
||||
preload: boolean;
|
||||
}
|
||||
|
||||
const cspSchema = Joi.object({
|
||||
enable: Joi.boolean().default(true).optional(),
|
||||
reportURI: Joi.string().optional(),
|
||||
});
|
||||
|
||||
export default registerAs('cspConfig', async () => {
|
||||
const cspConfig = cspSchema.validate(
|
||||
{
|
||||
enable: process.env.HD_CSP_ENABLE || true,
|
||||
reportURI: process.env.HD_CSP_REPORTURI,
|
||||
},
|
||||
{
|
||||
abortEarly: false,
|
||||
presence: 'required',
|
||||
},
|
||||
);
|
||||
if (cspConfig.error) {
|
||||
throw new Error(cspConfig.error.toString());
|
||||
}
|
||||
return cspConfig.value;
|
||||
});
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import * as Joi from 'joi';
|
||||
import { DatabaseDialect } from './database-dialect.enum';
|
||||
|
||||
export interface DatabaseConfig {
|
||||
username: string;
|
||||
password: string;
|
||||
database: string;
|
||||
host: string;
|
||||
port: number;
|
||||
storage: string;
|
||||
dialect: DatabaseDialect;
|
||||
}
|
||||
|
||||
export const databaseSchema = Joi.object({
|
||||
username: Joi.string(),
|
||||
password: Joi.string(),
|
||||
database: Joi.string(),
|
||||
host: Joi.string(),
|
||||
port: Joi.number(),
|
||||
storage: Joi.when('...dialect', {
|
||||
is: Joi.valid(DatabaseDialect.SQLITE),
|
||||
then: Joi.string(),
|
||||
otherwise: Joi.optional(),
|
||||
}),
|
||||
dialect: Joi.string().valid(...Object.values(DatabaseDialect)),
|
||||
});
|
||||
|
||||
export const appConfigDatabase = {
|
||||
username: process.env.HD_DATABASE_USER,
|
||||
password: process.env.HD_DATABASE_PASS,
|
||||
database: process.env.HD_DATABASE_NAME,
|
||||
host: process.env.HD_DATABASE_HOST,
|
||||
port: parseInt(process.env.HD_DATABASE_PORT) || undefined,
|
||||
storage: process.env.HD_DATABASE_STORAGE,
|
||||
dialect: process.env.HD_DATABASE_DIALECT,
|
||||
};
|
75
src/config/database.config.ts
Normal file
75
src/config/database.config.ts
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import * as Joi from 'joi';
|
||||
import { DatabaseDialect } from './database-dialect.enum';
|
||||
import { registerAs } from '@nestjs/config';
|
||||
|
||||
export interface DatabaseConfig {
|
||||
username: string;
|
||||
password: string;
|
||||
database: string;
|
||||
host: string;
|
||||
port: number;
|
||||
storage: string;
|
||||
dialect: DatabaseDialect;
|
||||
}
|
||||
|
||||
const databaseSchema = Joi.object({
|
||||
username: Joi.when('dialect', {
|
||||
is: Joi.invalid(DatabaseDialect.SQLITE),
|
||||
then: Joi.string(),
|
||||
otherwise: Joi.optional(),
|
||||
}),
|
||||
password: Joi.when('dialect', {
|
||||
is: Joi.invalid(DatabaseDialect.SQLITE),
|
||||
then: Joi.string(),
|
||||
otherwise: Joi.optional(),
|
||||
}),
|
||||
database: Joi.when('dialect', {
|
||||
is: Joi.invalid(DatabaseDialect.SQLITE),
|
||||
then: Joi.string(),
|
||||
otherwise: Joi.optional(),
|
||||
}),
|
||||
host: Joi.when('dialect', {
|
||||
is: Joi.invalid(DatabaseDialect.SQLITE),
|
||||
then: Joi.string(),
|
||||
otherwise: Joi.optional(),
|
||||
}),
|
||||
port: Joi.when('dialect', {
|
||||
is: Joi.invalid(DatabaseDialect.SQLITE),
|
||||
then: Joi.number(),
|
||||
otherwise: Joi.optional(),
|
||||
}),
|
||||
storage: Joi.when('dialect', {
|
||||
is: Joi.valid(DatabaseDialect.SQLITE),
|
||||
then: Joi.string(),
|
||||
otherwise: Joi.optional(),
|
||||
}),
|
||||
dialect: Joi.string().valid(...Object.values(DatabaseDialect)),
|
||||
});
|
||||
|
||||
export default registerAs('databaseConfig', async () => {
|
||||
const databaseConfig = databaseSchema.validate(
|
||||
{
|
||||
username: process.env.HD_DATABASE_USER,
|
||||
password: process.env.HD_DATABASE_PASS,
|
||||
database: process.env.HD_DATABASE_NAME,
|
||||
host: process.env.HD_DATABASE_HOST,
|
||||
port: parseInt(process.env.HD_DATABASE_PORT) || undefined,
|
||||
storage: process.env.HD_DATABASE_STORAGE,
|
||||
dialect: process.env.HD_DATABASE_DIALECT,
|
||||
},
|
||||
{
|
||||
abortEarly: false,
|
||||
presence: 'required',
|
||||
},
|
||||
);
|
||||
if (databaseConfig.error) {
|
||||
throw new Error(databaseConfig.error.toString());
|
||||
}
|
||||
return databaseConfig.value;
|
||||
});
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import * as Joi from 'joi';
|
||||
|
||||
export interface HstsConfig {
|
||||
enable: boolean;
|
||||
maxAgeSeconds: number;
|
||||
includeSubdomains: boolean;
|
||||
preload: boolean;
|
||||
}
|
||||
|
||||
export const hstsSchema = Joi.object({
|
||||
enable: Joi.boolean().default(true).optional(),
|
||||
maxAgeSeconds: Joi.number()
|
||||
.default(60 * 60 * 24 * 365)
|
||||
.optional(),
|
||||
includeSubdomains: Joi.boolean().default(true).optional(),
|
||||
preload: Joi.boolean().default(true).optional(),
|
||||
});
|
||||
|
||||
export const appConfigHsts = {
|
||||
enable: process.env.HD_HSTS_ENABLE,
|
||||
maxAgeSeconds: parseInt(process.env.HD_HSTS_MAX_AGE) || undefined,
|
||||
includeSubdomains: process.env.HD_HSTS_INCLUDE_SUBDOMAINS,
|
||||
preload: process.env.HD_HSTS_PRELOAD,
|
||||
};
|
43
src/config/hsts.config.ts
Normal file
43
src/config/hsts.config.ts
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import * as Joi from 'joi';
|
||||
import { registerAs } from '@nestjs/config';
|
||||
|
||||
export interface HstsConfig {
|
||||
enable: boolean;
|
||||
maxAgeSeconds: number;
|
||||
includeSubdomains: boolean;
|
||||
preload: boolean;
|
||||
}
|
||||
|
||||
const hstsSchema = Joi.object({
|
||||
enable: Joi.boolean().default(true).optional(),
|
||||
maxAgeSeconds: Joi.number()
|
||||
.default(60 * 60 * 24 * 365)
|
||||
.optional(),
|
||||
includeSubdomains: Joi.boolean().default(true).optional(),
|
||||
preload: Joi.boolean().default(true).optional(),
|
||||
});
|
||||
|
||||
export default registerAs('hstsConfig', async () => {
|
||||
const hstsConfig = hstsSchema.validate(
|
||||
{
|
||||
enable: process.env.HD_HSTS_ENABLE,
|
||||
maxAgeSeconds: parseInt(process.env.HD_HSTS_MAX_AGE) || undefined,
|
||||
includeSubdomains: process.env.HD_HSTS_INCLUDE_SUBDOMAINS,
|
||||
preload: process.env.HD_HSTS_PRELOAD,
|
||||
},
|
||||
{
|
||||
abortEarly: false,
|
||||
presence: 'required',
|
||||
},
|
||||
);
|
||||
if (hstsConfig.error) {
|
||||
throw new Error(hstsConfig.error.toString());
|
||||
}
|
||||
return hstsConfig.value;
|
||||
});
|
|
@ -1,11 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export enum LinkifyHeaderStyle {
|
||||
KEEP_CASE = 'keep-case',
|
||||
LOWER_CASE = 'lower-case',
|
||||
GFM = 'gfm',
|
||||
}
|
16
src/config/media.config.mock.ts
Normal file
16
src/config/media.config.mock.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { registerAs } from '@nestjs/config';
|
||||
|
||||
export default registerAs('mediaConfig', () => ({
|
||||
backend: {
|
||||
use: 'filesystem',
|
||||
filesystem: {
|
||||
uploadPath: 'uploads',
|
||||
},
|
||||
},
|
||||
}));
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
import * as Joi from 'joi';
|
||||
import { BackendType } from '../media/backends/backend-type.enum';
|
||||
import { registerAs } from '@nestjs/config';
|
||||
|
||||
export interface MediaConfig {
|
||||
backend: {
|
||||
|
@ -30,7 +31,7 @@ export interface MediaConfig {
|
|||
};
|
||||
}
|
||||
|
||||
export const mediaSchema = Joi.object({
|
||||
const mediaSchema = Joi.object({
|
||||
backend: {
|
||||
use: Joi.string().valid(...Object.values(BackendType)),
|
||||
filesystem: {
|
||||
|
@ -69,25 +70,38 @@ export const mediaSchema = Joi.object({
|
|||
},
|
||||
});
|
||||
|
||||
export const appConfigMedia = {
|
||||
backend: {
|
||||
use: process.env.HD_MEDIA_BACKEND,
|
||||
filesystem: {
|
||||
uploadPath: process.env.HD_MEDIA_BACKEND_FILESYSTEM_UPLOAD_PATH,
|
||||
export default registerAs('mediaConfig', async () => {
|
||||
const mediaConfig = mediaSchema.validate(
|
||||
{
|
||||
backend: {
|
||||
use: process.env.HD_MEDIA_BACKEND,
|
||||
filesystem: {
|
||||
uploadPath: process.env.HD_MEDIA_BACKEND_FILESYSTEM_UPLOAD_PATH,
|
||||
},
|
||||
s3: {
|
||||
accessKey: process.env.HD_MEDIA_BACKEND_S3_ACCESS_KEY,
|
||||
secretKey: process.env.HD_MEDIA_BACKEND_S3_ACCESS_KEY,
|
||||
endPoint: process.env.HD_MEDIA_BACKEND_S3_ENDPOINT,
|
||||
secure: process.env.HD_MEDIA_BACKEND_S3_SECURE,
|
||||
port: parseInt(process.env.HD_MEDIA_BACKEND_S3_PORT) || undefined,
|
||||
},
|
||||
azure: {
|
||||
connectionString:
|
||||
process.env.HD_MEDIA_BACKEND_AZURE_CONNECTION_STRING,
|
||||
container: process.env.HD_MEDIA_BACKEND_AZURE_CONTAINER,
|
||||
},
|
||||
imgur: {
|
||||
clientID: process.env.HD_MEDIA_BACKEND_IMGUR_CLIENTID,
|
||||
},
|
||||
},
|
||||
},
|
||||
s3: {
|
||||
accessKey: process.env.HD_MEDIA_BACKEND_S3_ACCESS_KEY,
|
||||
secretKey: process.env.HD_MEDIA_BACKEND_S3_ACCESS_KEY,
|
||||
endPoint: process.env.HD_MEDIA_BACKEND_S3_ENDPOINT,
|
||||
secure: process.env.HD_MEDIA_BACKEND_S3_SECURE,
|
||||
port: parseInt(process.env.HD_MEDIA_BACKEND_S3_PORT) || undefined,
|
||||
{
|
||||
abortEarly: false,
|
||||
presence: 'required',
|
||||
},
|
||||
azure: {
|
||||
connectionString: process.env.HD_MEDIA_BACKEND_AZURE_CONNECTION_STRING,
|
||||
container: process.env.HD_MEDIA_BACKEND_AZURE_CONTAINER,
|
||||
},
|
||||
imgur: {
|
||||
clientID: process.env.HD_MEDIA_BACKEND_IMGUR_CLIENTID,
|
||||
},
|
||||
},
|
||||
};
|
||||
);
|
||||
if (mediaConfig.error) {
|
||||
throw new Error(mediaConfig.error.toString());
|
||||
}
|
||||
return mediaConfig.value;
|
||||
});
|
|
@ -12,6 +12,7 @@ import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
|
|||
import { AppModule } from './app.module';
|
||||
import { AppConfig } from './config/app.config';
|
||||
import { NestConsoleLoggerService } from './logger/nest-console-logger.service';
|
||||
import { MediaConfig } from './config/media.config';
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create<NestExpressApplication>(AppModule);
|
||||
|
@ -20,6 +21,7 @@ async function bootstrap() {
|
|||
app.useLogger(logger);
|
||||
const configService = app.get(ConfigService);
|
||||
const appConfig = configService.get<AppConfig>('appConfig');
|
||||
const mediaConfig = configService.get<MediaConfig>('mediaConfig');
|
||||
|
||||
const swaggerOptions = new DocumentBuilder()
|
||||
.setTitle('HedgeDoc')
|
||||
|
@ -35,9 +37,9 @@ async function bootstrap() {
|
|||
transform: true,
|
||||
}),
|
||||
);
|
||||
if (appConfig.media.backend.use === 'filesystem') {
|
||||
if (mediaConfig.backend.use === 'filesystem') {
|
||||
app.useStaticAssets('uploads', {
|
||||
prefix: appConfig.media.backend.filesystem.uploadPath,
|
||||
prefix: mediaConfig.backend.filesystem.uploadPath,
|
||||
});
|
||||
}
|
||||
await app.listen(appConfig.port);
|
||||
|
|
|
@ -7,10 +7,11 @@
|
|||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { promises as fs } from 'fs';
|
||||
import { join } from 'path';
|
||||
import applicationConfig, { AppConfig } from '../../config/app.config';
|
||||
import mediaConfiguration from '../../config/media.config';
|
||||
import { ConsoleLoggerService } from '../../logger/console-logger.service';
|
||||
import { MediaBackend } from '../media-backend.interface';
|
||||
import { BackendData } from '../media-upload.entity';
|
||||
import { MediaConfig } from '../../config/media.config';
|
||||
|
||||
@Injectable()
|
||||
export class FilesystemBackend implements MediaBackend {
|
||||
|
@ -18,11 +19,11 @@ export class FilesystemBackend implements MediaBackend {
|
|||
|
||||
constructor(
|
||||
private readonly logger: ConsoleLoggerService,
|
||||
@Inject(applicationConfig.KEY)
|
||||
private appConfig: AppConfig,
|
||||
@Inject(mediaConfiguration.KEY)
|
||||
private mediaConfig: MediaConfig,
|
||||
) {
|
||||
this.logger.setContext(FilesystemBackend.name);
|
||||
this.uploadDirectory = appConfig.media.backend.filesystem.uploadPath;
|
||||
this.uploadDirectory = mediaConfig.backend.filesystem.uploadPath;
|
||||
}
|
||||
|
||||
async saveFile(
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
import { ConfigModule } from '@nestjs/config';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||
import appConfigMock from '../config/app.config.mock';
|
||||
import mediaConfigMock from '../config/media.config.mock';
|
||||
import { LoggerModule } from '../logger/logger.module';
|
||||
import { AuthorColor } from '../notes/author-color.entity';
|
||||
import { Note } from '../notes/note.entity';
|
||||
|
@ -39,7 +39,7 @@ describe('MediaService', () => {
|
|||
imports: [
|
||||
ConfigModule.forRoot({
|
||||
isGlobal: true,
|
||||
load: [appConfigMock],
|
||||
load: [mediaConfigMock],
|
||||
}),
|
||||
LoggerModule,
|
||||
NotesModule,
|
||||
|
|
|
@ -9,7 +9,7 @@ import { ModuleRef } from '@nestjs/core';
|
|||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import * as FileType from 'file-type';
|
||||
import { Repository } from 'typeorm';
|
||||
import applicationConfig, { AppConfig } from '../config/app.config';
|
||||
import mediaConfiguration, { MediaConfig } from '../config/media.config';
|
||||
import { ClientError, NotInDBError, PermissionError } from '../errors/errors';
|
||||
import { ConsoleLoggerService } from '../logger/console-logger.service';
|
||||
import { NotesService } from '../notes/notes.service';
|
||||
|
@ -31,8 +31,8 @@ export class MediaService {
|
|||
private notesService: NotesService,
|
||||
private usersService: UsersService,
|
||||
private moduleRef: ModuleRef,
|
||||
@Inject(applicationConfig.KEY)
|
||||
private appConfig: AppConfig,
|
||||
@Inject(mediaConfiguration.KEY)
|
||||
private mediaConfig: MediaConfig,
|
||||
) {
|
||||
this.logger.setContext(MediaService.name);
|
||||
this.mediaBackendType = this.chooseBackendType();
|
||||
|
@ -120,7 +120,7 @@ export class MediaService {
|
|||
}
|
||||
|
||||
private chooseBackendType(): BackendType {
|
||||
switch (this.appConfig.media.backend.use) {
|
||||
switch (this.mediaConfig.backend.use) {
|
||||
case 'filesystem':
|
||||
return BackendType.FILESYSTEM;
|
||||
}
|
||||
|
|
|
@ -4,14 +4,14 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { ConfigModule, registerAs } from '@nestjs/config';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { NestExpressApplication } from '@nestjs/platform-express';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { promises as fs } from 'fs';
|
||||
import * as request from 'supertest';
|
||||
import { PublicApiModule } from '../../src/api/public/public-api.module';
|
||||
import appConfigMock from '../../src/config/app.config.mock';
|
||||
import mediaConfigMock from '../../src/config/media.config.mock';
|
||||
import { GroupsModule } from '../../src/groups/groups.module';
|
||||
import { LoggerModule } from '../../src/logger/logger.module';
|
||||
import { NestConsoleLoggerService } from '../../src/logger/nest-console-logger.service';
|
||||
|
@ -31,7 +31,7 @@ describe('Notes', () => {
|
|||
imports: [
|
||||
ConfigModule.forRoot({
|
||||
isGlobal: true,
|
||||
load: [appConfigMock],
|
||||
load: [mediaConfigMock],
|
||||
}),
|
||||
PublicApiModule,
|
||||
MediaModule,
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
*/
|
||||
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { ConfigModule, registerAs } from '@nestjs/config';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import * as request from 'supertest';
|
||||
import { PublicApiModule } from '../../src/api/public/public-api.module';
|
||||
import appConfigMock from '../../src/config/app.config.mock';
|
||||
import mediaConfigMock from '../../src/config/media.config.mock';
|
||||
import { NotInDBError } from '../../src/errors/errors';
|
||||
import { GroupsModule } from '../../src/groups/groups.module';
|
||||
import { LoggerModule } from '../../src/logger/logger.module';
|
||||
|
@ -27,7 +27,7 @@ describe('Notes', () => {
|
|||
imports: [
|
||||
ConfigModule.forRoot({
|
||||
isGlobal: true,
|
||||
load: [appConfigMock],
|
||||
load: [mediaConfigMock],
|
||||
}),
|
||||
PublicApiModule,
|
||||
NotesModule,
|
||||
|
|
Loading…
Reference in a new issue