mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-16 16:14:43 -04:00
fix(repository): Move backend code into subdirectory
Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
parent
86584e705f
commit
bf30cbcf48
272 changed files with 87 additions and 67 deletions
182
backend/src/frontend-config/frontend-config.dto.ts
Normal file
182
backend/src/frontend-config/frontend-config.dto.ts
Normal file
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import {
|
||||
IsArray,
|
||||
IsBoolean,
|
||||
IsNumber,
|
||||
IsOptional,
|
||||
IsString,
|
||||
IsUrl,
|
||||
ValidateNested,
|
||||
} from 'class-validator';
|
||||
import { URL } from 'url';
|
||||
|
||||
import { GuestAccess } from '../config/guest_access.enum';
|
||||
import { ServerVersion } from '../monitoring/server-status.dto';
|
||||
import { BaseDto } from '../utils/base.dto.';
|
||||
|
||||
export enum AuthProviderType {
|
||||
LOCAL = 'local',
|
||||
LDAP = 'ldap',
|
||||
SAML = 'saml',
|
||||
OAUTH2 = 'oauth2',
|
||||
GITLAB = 'gitlab',
|
||||
FACEBOOK = 'facebook',
|
||||
GITHUB = 'github',
|
||||
TWITTER = 'twitter',
|
||||
DROPBOX = 'dropbox',
|
||||
GOOGLE = 'google',
|
||||
}
|
||||
|
||||
export type AuthProviderTypeWithCustomName =
|
||||
| AuthProviderType.LDAP
|
||||
| AuthProviderType.OAUTH2
|
||||
| AuthProviderType.SAML
|
||||
| AuthProviderType.GITLAB;
|
||||
|
||||
export type AuthProviderTypeWithoutCustomName =
|
||||
| AuthProviderType.LOCAL
|
||||
| AuthProviderType.FACEBOOK
|
||||
| AuthProviderType.GITHUB
|
||||
| AuthProviderType.TWITTER
|
||||
| AuthProviderType.DROPBOX
|
||||
| AuthProviderType.GOOGLE;
|
||||
|
||||
export class AuthProviderWithoutCustomNameDto extends BaseDto {
|
||||
/**
|
||||
* The type of the auth provider.
|
||||
*/
|
||||
@IsString()
|
||||
type: AuthProviderTypeWithoutCustomName;
|
||||
}
|
||||
|
||||
export class AuthProviderWithCustomNameDto extends BaseDto {
|
||||
/**
|
||||
* The type of the auth provider.
|
||||
*/
|
||||
@IsString()
|
||||
type: AuthProviderTypeWithCustomName;
|
||||
|
||||
/**
|
||||
* The identifier with which the auth provider can be called
|
||||
* @example gitlab-fsorg
|
||||
*/
|
||||
@IsString()
|
||||
identifier: string;
|
||||
|
||||
/**
|
||||
* The name given to the auth provider
|
||||
* @example GitLab fachschaften.org
|
||||
*/
|
||||
@IsString()
|
||||
providerName: string;
|
||||
}
|
||||
|
||||
export type AuthProviderDto =
|
||||
| AuthProviderWithCustomNameDto
|
||||
| AuthProviderWithoutCustomNameDto;
|
||||
|
||||
export class BrandingDto extends BaseDto {
|
||||
/**
|
||||
* The name to be displayed next to the HedgeDoc logo
|
||||
* @example ACME Corp
|
||||
*/
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
name?: string;
|
||||
|
||||
/**
|
||||
* The logo to be displayed next to the HedgeDoc logo
|
||||
* @example https://md.example.com/logo.png
|
||||
*/
|
||||
@IsUrl()
|
||||
@IsOptional()
|
||||
logo?: URL;
|
||||
}
|
||||
|
||||
export class SpecialUrlsDto extends BaseDto {
|
||||
/**
|
||||
* A link to the privacy notice
|
||||
* @example https://md.example.com/n/privacy
|
||||
*/
|
||||
@IsUrl()
|
||||
@IsOptional()
|
||||
privacy?: URL;
|
||||
|
||||
/**
|
||||
* A link to the terms of use
|
||||
* @example https://md.example.com/n/termsOfUse
|
||||
*/
|
||||
@IsUrl()
|
||||
@IsOptional()
|
||||
termsOfUse?: URL;
|
||||
|
||||
/**
|
||||
* A link to the imprint
|
||||
* @example https://md.example.com/n/imprint
|
||||
*/
|
||||
@IsUrl()
|
||||
@IsOptional()
|
||||
imprint?: URL;
|
||||
}
|
||||
|
||||
export class FrontendConfigDto extends BaseDto {
|
||||
/**
|
||||
* Maximum access level for guest users
|
||||
*/
|
||||
@IsString()
|
||||
guestAccess: GuestAccess;
|
||||
|
||||
/**
|
||||
* Are users allowed to register on this instance?
|
||||
*/
|
||||
@IsBoolean()
|
||||
allowRegister: boolean;
|
||||
|
||||
/**
|
||||
* Which auth providers are enabled and how are they configured?
|
||||
*/
|
||||
@IsArray()
|
||||
@ValidateNested({ each: true })
|
||||
authProviders: AuthProviderDto[];
|
||||
|
||||
/**
|
||||
* Individual branding information
|
||||
*/
|
||||
@ValidateNested()
|
||||
branding: BrandingDto;
|
||||
|
||||
/**
|
||||
* Is an image proxy enabled?
|
||||
*/
|
||||
@IsBoolean()
|
||||
useImageProxy: boolean;
|
||||
|
||||
/**
|
||||
* Links to some special pages
|
||||
*/
|
||||
@ValidateNested()
|
||||
specialUrls: SpecialUrlsDto;
|
||||
|
||||
/**
|
||||
* The version of HedgeDoc
|
||||
*/
|
||||
@ValidateNested()
|
||||
version: ServerVersion;
|
||||
|
||||
/**
|
||||
* The plantUML server that should be used to render.
|
||||
*/
|
||||
@IsUrl()
|
||||
@IsOptional()
|
||||
plantUmlServer?: URL;
|
||||
|
||||
/**
|
||||
* The maximal length of each document
|
||||
*/
|
||||
@IsNumber()
|
||||
maxDocumentLength: number;
|
||||
}
|
17
backend/src/frontend-config/frontend-config.module.ts
Normal file
17
backend/src/frontend-config/frontend-config.module.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
|
||||
import { LoggerModule } from '../logger/logger.module';
|
||||
import { FrontendConfigService } from './frontend-config.service';
|
||||
|
||||
@Module({
|
||||
imports: [LoggerModule, ConfigModule],
|
||||
providers: [FrontendConfigService],
|
||||
exports: [FrontendConfigService],
|
||||
})
|
||||
export class FrontendConfigModule {}
|
423
backend/src/frontend-config/frontend-config.service.spec.ts
Normal file
423
backend/src/frontend-config/frontend-config.service.spec.ts
Normal file
|
@ -0,0 +1,423 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { ConfigModule, registerAs } from '@nestjs/config';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { URL } from 'url';
|
||||
|
||||
import { AppConfig } from '../config/app.config';
|
||||
import { AuthConfig } from '../config/auth.config';
|
||||
import { CustomizationConfig } from '../config/customization.config';
|
||||
import { DefaultAccessPermission } from '../config/default-access-permission.enum';
|
||||
import { ExternalServicesConfig } from '../config/external-services.config';
|
||||
import { GitlabScope, GitlabVersion } from '../config/gitlab.enum';
|
||||
import { GuestAccess } from '../config/guest_access.enum';
|
||||
import { Loglevel } from '../config/loglevel.enum';
|
||||
import { NoteConfig } from '../config/note.config';
|
||||
import { LoggerModule } from '../logger/logger.module';
|
||||
import { getServerVersionFromPackageJson } from '../utils/serverVersion';
|
||||
import { AuthProviderType } from './frontend-config.dto';
|
||||
import { FrontendConfigService } from './frontend-config.service';
|
||||
|
||||
/* eslint-disable
|
||||
jest/no-conditional-expect
|
||||
*/
|
||||
|
||||
describe('FrontendConfigService', () => {
|
||||
const domain = 'http://md.example.com';
|
||||
const emptyAuthConfig: AuthConfig = {
|
||||
session: {
|
||||
secret: 'my-secret',
|
||||
lifetime: 1209600000,
|
||||
},
|
||||
local: {
|
||||
enableLogin: false,
|
||||
enableRegister: false,
|
||||
minimalPasswordStrength: 2,
|
||||
},
|
||||
facebook: {
|
||||
clientID: undefined,
|
||||
clientSecret: undefined,
|
||||
},
|
||||
twitter: {
|
||||
consumerKey: undefined,
|
||||
consumerSecret: undefined,
|
||||
},
|
||||
github: {
|
||||
clientID: undefined,
|
||||
clientSecret: undefined,
|
||||
},
|
||||
dropbox: {
|
||||
clientID: undefined,
|
||||
clientSecret: undefined,
|
||||
appKey: undefined,
|
||||
},
|
||||
google: {
|
||||
clientID: undefined,
|
||||
clientSecret: undefined,
|
||||
apiKey: undefined,
|
||||
},
|
||||
gitlab: [],
|
||||
ldap: [],
|
||||
saml: [],
|
||||
oauth2: [],
|
||||
};
|
||||
|
||||
describe('getAuthProviders', () => {
|
||||
const facebook: AuthConfig['facebook'] = {
|
||||
clientID: 'facebookTestId',
|
||||
clientSecret: 'facebookTestSecret',
|
||||
};
|
||||
const twitter: AuthConfig['twitter'] = {
|
||||
consumerKey: 'twitterTestId',
|
||||
consumerSecret: 'twitterTestSecret',
|
||||
};
|
||||
const github: AuthConfig['github'] = {
|
||||
clientID: 'githubTestId',
|
||||
clientSecret: 'githubTestSecret',
|
||||
};
|
||||
const dropbox: AuthConfig['dropbox'] = {
|
||||
clientID: 'dropboxTestId',
|
||||
clientSecret: 'dropboxTestSecret',
|
||||
appKey: 'dropboxTestKey',
|
||||
};
|
||||
const google: AuthConfig['google'] = {
|
||||
clientID: 'googleTestId',
|
||||
clientSecret: 'googleTestSecret',
|
||||
apiKey: 'googleTestKey',
|
||||
};
|
||||
const gitlab: AuthConfig['gitlab'] = [
|
||||
{
|
||||
identifier: 'gitlabTestIdentifier',
|
||||
providerName: 'gitlabTestName',
|
||||
baseURL: 'gitlabTestUrl',
|
||||
clientID: 'gitlabTestId',
|
||||
clientSecret: 'gitlabTestSecret',
|
||||
scope: GitlabScope.API,
|
||||
version: GitlabVersion.V4,
|
||||
},
|
||||
];
|
||||
const ldap: AuthConfig['ldap'] = [
|
||||
{
|
||||
identifier: 'ldapTestIdentifier',
|
||||
providerName: 'ldapTestName',
|
||||
url: 'ldapTestUrl',
|
||||
bindDn: 'ldapTestBindDn',
|
||||
bindCredentials: 'ldapTestBindCredentials',
|
||||
searchBase: 'ldapTestSearchBase',
|
||||
searchFilter: 'ldapTestSearchFilter',
|
||||
searchAttributes: ['ldapTestSearchAttribute'],
|
||||
userIdField: 'ldapTestUserId',
|
||||
displayNameField: 'ldapTestDisplayName',
|
||||
profilePictureField: 'ldapTestProfilePicture',
|
||||
tlsCaCerts: ['ldapTestTlsCa'],
|
||||
},
|
||||
];
|
||||
const saml: AuthConfig['saml'] = [
|
||||
{
|
||||
identifier: 'samlTestIdentifier',
|
||||
providerName: 'samlTestName',
|
||||
idpSsoUrl: 'samlTestUrl',
|
||||
idpCert: 'samlTestCert',
|
||||
clientCert: 'samlTestClientCert',
|
||||
issuer: 'samlTestIssuer',
|
||||
identifierFormat: 'samlTestUrl',
|
||||
disableRequestedAuthnContext: 'samlTestUrl',
|
||||
groupAttribute: 'samlTestUrl',
|
||||
requiredGroups: ['samlTestUrl'],
|
||||
externalGroups: ['samlTestUrl'],
|
||||
attribute: {
|
||||
id: 'samlTestUrl',
|
||||
username: 'samlTestUrl',
|
||||
email: 'samlTestUrl',
|
||||
},
|
||||
},
|
||||
];
|
||||
const oauth2: AuthConfig['oauth2'] = [
|
||||
{
|
||||
identifier: 'oauth2Testidentifier',
|
||||
providerName: 'oauth2TestName',
|
||||
baseURL: 'oauth2TestUrl',
|
||||
userProfileURL: 'oauth2TestProfileUrl',
|
||||
userProfileIdAttr: 'oauth2TestProfileId',
|
||||
userProfileUsernameAttr: 'oauth2TestProfileUsername',
|
||||
userProfileDisplayNameAttr: 'oauth2TestProfileDisplay',
|
||||
userProfileEmailAttr: 'oauth2TestProfileEmail',
|
||||
tokenURL: 'oauth2TestTokenUrl',
|
||||
authorizationURL: 'oauth2TestAuthUrl',
|
||||
clientID: 'oauth2TestId',
|
||||
clientSecret: 'oauth2TestSecret',
|
||||
scope: 'oauth2TestScope',
|
||||
rolesClaim: 'oauth2TestRoles',
|
||||
accessRole: 'oauth2TestAccess',
|
||||
},
|
||||
];
|
||||
for (const authConfigConfigured of [
|
||||
facebook,
|
||||
twitter,
|
||||
github,
|
||||
dropbox,
|
||||
google,
|
||||
gitlab,
|
||||
ldap,
|
||||
saml,
|
||||
oauth2,
|
||||
]) {
|
||||
it(`works with ${JSON.stringify(authConfigConfigured)}`, async () => {
|
||||
const appConfig: AppConfig = {
|
||||
domain: domain,
|
||||
rendererBaseUrl: 'https://renderer.example.org',
|
||||
port: 3000,
|
||||
loglevel: Loglevel.ERROR,
|
||||
persistInterval: 10,
|
||||
};
|
||||
const authConfig: AuthConfig = {
|
||||
...emptyAuthConfig,
|
||||
...authConfigConfigured,
|
||||
};
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
imports: [
|
||||
ConfigModule.forRoot({
|
||||
isGlobal: true,
|
||||
load: [
|
||||
registerAs('appConfig', () => appConfig),
|
||||
registerAs('authConfig', () => authConfig),
|
||||
registerAs('customizationConfig', () => {
|
||||
return { branding: {}, specialUrls: {} };
|
||||
}),
|
||||
registerAs('externalServicesConfig', () => {
|
||||
return {};
|
||||
}),
|
||||
registerAs('noteConfig', () => {
|
||||
return {
|
||||
forbiddenNoteIds: [],
|
||||
maxDocumentLength: 200,
|
||||
guestAccess: GuestAccess.CREATE,
|
||||
permissions: {
|
||||
default: {
|
||||
everyone: DefaultAccessPermission.READ,
|
||||
loggedIn: DefaultAccessPermission.WRITE,
|
||||
},
|
||||
},
|
||||
} as NoteConfig;
|
||||
}),
|
||||
],
|
||||
}),
|
||||
LoggerModule,
|
||||
],
|
||||
providers: [FrontendConfigService],
|
||||
}).compile();
|
||||
const service = module.get(FrontendConfigService);
|
||||
const config = await service.getFrontendConfig();
|
||||
if (authConfig.dropbox.clientID) {
|
||||
expect(config.authProviders).toContainEqual({
|
||||
type: AuthProviderType.DROPBOX,
|
||||
});
|
||||
}
|
||||
if (authConfig.facebook.clientID) {
|
||||
expect(config.authProviders).toContainEqual({
|
||||
type: AuthProviderType.FACEBOOK,
|
||||
});
|
||||
}
|
||||
if (authConfig.google.clientID) {
|
||||
expect(config.authProviders).toContainEqual({
|
||||
type: AuthProviderType.GOOGLE,
|
||||
});
|
||||
}
|
||||
if (authConfig.github.clientID) {
|
||||
expect(config.authProviders).toContainEqual({
|
||||
type: AuthProviderType.GITHUB,
|
||||
});
|
||||
}
|
||||
if (authConfig.local.enableLogin) {
|
||||
expect(config.authProviders).toContainEqual({
|
||||
type: AuthProviderType.LOCAL,
|
||||
});
|
||||
}
|
||||
if (authConfig.twitter.consumerKey) {
|
||||
expect(config.authProviders).toContainEqual({
|
||||
type: AuthProviderType.TWITTER,
|
||||
});
|
||||
}
|
||||
expect(
|
||||
config.authProviders.filter(
|
||||
(provider) => provider.type === AuthProviderType.GITLAB,
|
||||
).length,
|
||||
).toEqual(authConfig.gitlab.length);
|
||||
expect(
|
||||
config.authProviders.filter(
|
||||
(provider) => provider.type === AuthProviderType.LDAP,
|
||||
).length,
|
||||
).toEqual(authConfig.ldap.length);
|
||||
expect(
|
||||
config.authProviders.filter(
|
||||
(provider) => provider.type === AuthProviderType.SAML,
|
||||
).length,
|
||||
).toEqual(authConfig.saml.length);
|
||||
expect(
|
||||
config.authProviders.filter(
|
||||
(provider) => provider.type === AuthProviderType.OAUTH2,
|
||||
).length,
|
||||
).toEqual(authConfig.oauth2.length);
|
||||
if (authConfig.gitlab.length > 0) {
|
||||
expect(
|
||||
config.authProviders.find(
|
||||
(provider) => provider.type === AuthProviderType.GITLAB,
|
||||
),
|
||||
).toEqual({
|
||||
type: AuthProviderType.GITLAB,
|
||||
providerName: authConfig.gitlab[0].providerName,
|
||||
identifier: authConfig.gitlab[0].identifier,
|
||||
});
|
||||
}
|
||||
if (authConfig.ldap.length > 0) {
|
||||
expect(
|
||||
config.authProviders.find(
|
||||
(provider) => provider.type === AuthProviderType.LDAP,
|
||||
),
|
||||
).toEqual({
|
||||
type: AuthProviderType.LDAP,
|
||||
providerName: authConfig.ldap[0].providerName,
|
||||
identifier: authConfig.ldap[0].identifier,
|
||||
});
|
||||
}
|
||||
if (authConfig.saml.length > 0) {
|
||||
expect(
|
||||
config.authProviders.find(
|
||||
(provider) => provider.type === AuthProviderType.SAML,
|
||||
),
|
||||
).toEqual({
|
||||
type: AuthProviderType.SAML,
|
||||
providerName: authConfig.saml[0].providerName,
|
||||
identifier: authConfig.saml[0].identifier,
|
||||
});
|
||||
}
|
||||
if (authConfig.oauth2.length > 0) {
|
||||
expect(
|
||||
config.authProviders.find(
|
||||
(provider) => provider.type === AuthProviderType.OAUTH2,
|
||||
),
|
||||
).toEqual({
|
||||
type: AuthProviderType.OAUTH2,
|
||||
providerName: authConfig.oauth2[0].providerName,
|
||||
identifier: authConfig.oauth2[0].identifier,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const maxDocumentLength = 100000;
|
||||
const enableRegister = true;
|
||||
const imageProxy = 'https://imageProxy.example.com';
|
||||
const customName = 'Test Branding Name';
|
||||
|
||||
let index = 1;
|
||||
for (const customLogo of [undefined, 'https://example.com/logo.png']) {
|
||||
for (const privacyLink of [undefined, 'https://example.com/privacy']) {
|
||||
for (const termsOfUseLink of [undefined, 'https://example.com/terms']) {
|
||||
for (const imprintLink of [undefined, 'https://example.com/imprint']) {
|
||||
for (const plantUmlServer of [
|
||||
undefined,
|
||||
'https://plantuml.example.com',
|
||||
]) {
|
||||
it(`combination #${index} works`, async () => {
|
||||
const appConfig: AppConfig = {
|
||||
domain: domain,
|
||||
rendererBaseUrl: 'https://renderer.example.org',
|
||||
port: 3000,
|
||||
loglevel: Loglevel.ERROR,
|
||||
persistInterval: 10,
|
||||
};
|
||||
const authConfig: AuthConfig = {
|
||||
...emptyAuthConfig,
|
||||
local: {
|
||||
enableLogin: true,
|
||||
enableRegister,
|
||||
minimalPasswordStrength: 3,
|
||||
},
|
||||
};
|
||||
const customizationConfig: CustomizationConfig = {
|
||||
branding: {
|
||||
customName: customName,
|
||||
customLogo: customLogo,
|
||||
},
|
||||
specialUrls: {
|
||||
privacy: privacyLink,
|
||||
termsOfUse: termsOfUseLink,
|
||||
imprint: imprintLink,
|
||||
},
|
||||
};
|
||||
const externalServicesConfig: ExternalServicesConfig = {
|
||||
plantUmlServer: plantUmlServer,
|
||||
imageProxy: imageProxy,
|
||||
};
|
||||
const noteConfig: NoteConfig = {
|
||||
forbiddenNoteIds: [],
|
||||
maxDocumentLength: maxDocumentLength,
|
||||
guestAccess: GuestAccess.CREATE,
|
||||
permissions: {
|
||||
default: {
|
||||
everyone: DefaultAccessPermission.READ,
|
||||
loggedIn: DefaultAccessPermission.WRITE,
|
||||
},
|
||||
},
|
||||
};
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
imports: [
|
||||
ConfigModule.forRoot({
|
||||
isGlobal: true,
|
||||
load: [
|
||||
registerAs('appConfig', () => appConfig),
|
||||
registerAs('authConfig', () => authConfig),
|
||||
registerAs(
|
||||
'customizationConfig',
|
||||
() => customizationConfig,
|
||||
),
|
||||
registerAs(
|
||||
'externalServicesConfig',
|
||||
() => externalServicesConfig,
|
||||
),
|
||||
registerAs('noteConfig', () => noteConfig),
|
||||
],
|
||||
}),
|
||||
LoggerModule,
|
||||
],
|
||||
providers: [FrontendConfigService],
|
||||
}).compile();
|
||||
|
||||
const service = module.get(FrontendConfigService);
|
||||
const config = await service.getFrontendConfig();
|
||||
expect(config.allowRegister).toEqual(enableRegister);
|
||||
expect(config.guestAccess).toEqual(noteConfig.guestAccess);
|
||||
expect(config.branding.name).toEqual(customName);
|
||||
expect(config.branding.logo).toEqual(
|
||||
customLogo ? new URL(customLogo) : undefined,
|
||||
);
|
||||
expect(config.maxDocumentLength).toEqual(maxDocumentLength);
|
||||
expect(config.plantUmlServer).toEqual(
|
||||
plantUmlServer ? new URL(plantUmlServer) : undefined,
|
||||
);
|
||||
expect(config.specialUrls.imprint).toEqual(
|
||||
imprintLink ? new URL(imprintLink) : undefined,
|
||||
);
|
||||
expect(config.specialUrls.privacy).toEqual(
|
||||
privacyLink ? new URL(privacyLink) : undefined,
|
||||
);
|
||||
expect(config.specialUrls.termsOfUse).toEqual(
|
||||
termsOfUseLink ? new URL(termsOfUseLink) : undefined,
|
||||
);
|
||||
expect(config.useImageProxy).toEqual(!!imageProxy);
|
||||
expect(config.version).toEqual(
|
||||
await getServerVersionFromPackageJson(),
|
||||
);
|
||||
});
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
147
backend/src/frontend-config/frontend-config.service.ts
Normal file
147
backend/src/frontend-config/frontend-config.service.ts
Normal file
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { URL } from 'url';
|
||||
|
||||
import appConfiguration, { AppConfig } from '../config/app.config';
|
||||
import authConfiguration, { AuthConfig } from '../config/auth.config';
|
||||
import customizationConfiguration, {
|
||||
CustomizationConfig,
|
||||
} from '../config/customization.config';
|
||||
import externalServicesConfiguration, {
|
||||
ExternalServicesConfig,
|
||||
} from '../config/external-services.config';
|
||||
import noteConfiguration, { NoteConfig } from '../config/note.config';
|
||||
import { ConsoleLoggerService } from '../logger/console-logger.service';
|
||||
import { getServerVersionFromPackageJson } from '../utils/serverVersion';
|
||||
import {
|
||||
AuthProviderDto,
|
||||
AuthProviderType,
|
||||
BrandingDto,
|
||||
FrontendConfigDto,
|
||||
SpecialUrlsDto,
|
||||
} from './frontend-config.dto';
|
||||
|
||||
@Injectable()
|
||||
export class FrontendConfigService {
|
||||
constructor(
|
||||
private readonly logger: ConsoleLoggerService,
|
||||
@Inject(appConfiguration.KEY)
|
||||
private appConfig: AppConfig,
|
||||
@Inject(noteConfiguration.KEY)
|
||||
private noteConfig: NoteConfig,
|
||||
@Inject(authConfiguration.KEY)
|
||||
private authConfig: AuthConfig,
|
||||
@Inject(customizationConfiguration.KEY)
|
||||
private customizationConfig: CustomizationConfig,
|
||||
@Inject(externalServicesConfiguration.KEY)
|
||||
private externalServicesConfig: ExternalServicesConfig,
|
||||
) {
|
||||
this.logger.setContext(FrontendConfigService.name);
|
||||
}
|
||||
|
||||
async getFrontendConfig(): Promise<FrontendConfigDto> {
|
||||
return {
|
||||
guestAccess: this.noteConfig.guestAccess,
|
||||
allowRegister: this.authConfig.local.enableRegister,
|
||||
authProviders: this.getAuthProviders(),
|
||||
branding: this.getBranding(),
|
||||
maxDocumentLength: this.noteConfig.maxDocumentLength,
|
||||
plantUmlServer: this.externalServicesConfig.plantUmlServer
|
||||
? new URL(this.externalServicesConfig.plantUmlServer)
|
||||
: undefined,
|
||||
specialUrls: this.getSpecialUrls(),
|
||||
useImageProxy: !!this.externalServicesConfig.imageProxy,
|
||||
version: await getServerVersionFromPackageJson(),
|
||||
};
|
||||
}
|
||||
|
||||
private getAuthProviders(): AuthProviderDto[] {
|
||||
const providers: AuthProviderDto[] = [];
|
||||
if (this.authConfig.local.enableLogin) {
|
||||
providers.push({
|
||||
type: AuthProviderType.LOCAL,
|
||||
});
|
||||
}
|
||||
if (this.authConfig.dropbox.clientID) {
|
||||
providers.push({
|
||||
type: AuthProviderType.DROPBOX,
|
||||
});
|
||||
}
|
||||
if (this.authConfig.facebook.clientID) {
|
||||
providers.push({
|
||||
type: AuthProviderType.FACEBOOK,
|
||||
});
|
||||
}
|
||||
if (this.authConfig.github.clientID) {
|
||||
providers.push({
|
||||
type: AuthProviderType.GITHUB,
|
||||
});
|
||||
}
|
||||
if (this.authConfig.google.clientID) {
|
||||
providers.push({
|
||||
type: AuthProviderType.GOOGLE,
|
||||
});
|
||||
}
|
||||
if (this.authConfig.twitter.consumerKey) {
|
||||
providers.push({
|
||||
type: AuthProviderType.TWITTER,
|
||||
});
|
||||
}
|
||||
this.authConfig.gitlab.forEach((gitLabEntry) => {
|
||||
providers.push({
|
||||
type: AuthProviderType.GITLAB,
|
||||
providerName: gitLabEntry.providerName,
|
||||
identifier: gitLabEntry.identifier,
|
||||
});
|
||||
});
|
||||
this.authConfig.ldap.forEach((ldapEntry) => {
|
||||
providers.push({
|
||||
type: AuthProviderType.LDAP,
|
||||
providerName: ldapEntry.providerName,
|
||||
identifier: ldapEntry.identifier,
|
||||
});
|
||||
});
|
||||
this.authConfig.oauth2.forEach((oauth2Entry) => {
|
||||
providers.push({
|
||||
type: AuthProviderType.OAUTH2,
|
||||
providerName: oauth2Entry.providerName,
|
||||
identifier: oauth2Entry.identifier,
|
||||
});
|
||||
});
|
||||
this.authConfig.saml.forEach((samlEntry) => {
|
||||
providers.push({
|
||||
type: AuthProviderType.SAML,
|
||||
providerName: samlEntry.providerName,
|
||||
identifier: samlEntry.identifier,
|
||||
});
|
||||
});
|
||||
return providers;
|
||||
}
|
||||
|
||||
private getBranding(): BrandingDto {
|
||||
return {
|
||||
logo: this.customizationConfig.branding.customLogo
|
||||
? new URL(this.customizationConfig.branding.customLogo)
|
||||
: undefined,
|
||||
name: this.customizationConfig.branding.customName,
|
||||
};
|
||||
}
|
||||
|
||||
private getSpecialUrls(): SpecialUrlsDto {
|
||||
return {
|
||||
imprint: this.customizationConfig.specialUrls.imprint
|
||||
? new URL(this.customizationConfig.specialUrls.imprint)
|
||||
: undefined,
|
||||
privacy: this.customizationConfig.specialUrls.privacy
|
||||
? new URL(this.customizationConfig.specialUrls.privacy)
|
||||
: undefined,
|
||||
termsOfUse: this.customizationConfig.specialUrls.termsOfUse
|
||||
? new URL(this.customizationConfig.specialUrls.termsOfUse)
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue