diff --git a/backend/src/config/auth.config.ts b/backend/src/config/auth.config.ts index 4e91965f1..e561f627b 100644 --- a/backend/src/config/auth.config.ts +++ b/backend/src/config/auth.config.ts @@ -10,6 +10,7 @@ import * as Joi from 'joi'; import { GitlabScope, GitlabVersion } from './gitlab.enum'; import { buildErrorMessage, + ensureNoDuplicatesExist, parseOptionalNumber, replaceAuthErrorsWithEnvironmentVariables, toArrayConfig, @@ -217,7 +218,6 @@ const authSchema = Joi.object({ }); export default registerAs('authConfig', () => { - // ToDo: Validate these with Joi to prevent duplicate entries? const gitlabNames = ( toArrayConfig(process.env.HD_AUTH_GITLABS, ',') ?? [] ).map((name) => name.toUpperCase()); @@ -226,9 +226,13 @@ export default registerAs('authConfig', () => { "GitLab auth is currently not yet supported. Please don't configure it", ); } + ensureNoDuplicatesExist('GitLab', gitlabNames); + const ldapNames = ( toArrayConfig(process.env.HD_AUTH_LDAP_SERVERS, ',') ?? [] ).map((name) => name.toUpperCase()); + ensureNoDuplicatesExist('LDAP', ldapNames); + const samlNames = (toArrayConfig(process.env.HD_AUTH_SAMLS, ',') ?? []).map( (name) => name.toUpperCase(), ); @@ -237,6 +241,8 @@ export default registerAs('authConfig', () => { "SAML auth is currently not yet supported. Please don't configure it", ); } + ensureNoDuplicatesExist('SAML', samlNames); + const oauth2Names = ( toArrayConfig(process.env.HD_AUTH_OAUTH2S, ',') ?? [] ).map((name) => name.toUpperCase()); @@ -245,6 +251,7 @@ export default registerAs('authConfig', () => { "OAuth2 auth is currently not yet supported. Please don't configure it", ); } + ensureNoDuplicatesExist('OAuth2', oauth2Names); const gitlabs = gitlabNames.map((gitlabName) => { return { diff --git a/backend/src/config/utils.spec.ts b/backend/src/config/utils.spec.ts index 6249611cc..62a57b030 100644 --- a/backend/src/config/utils.spec.ts +++ b/backend/src/config/utils.spec.ts @@ -1,10 +1,12 @@ /* - * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ import { Loglevel } from './loglevel.enum'; import { + ensureNoDuplicatesExist, + findDuplicatesInArray, needToLog, parseOptionalNumber, replaceAuthErrorsWithEnvironmentVariables, @@ -12,6 +14,39 @@ import { } from './utils'; describe('config utils', () => { + describe('findDuplicatesInArray', () => { + it('empty array', () => { + expect(findDuplicatesInArray([])).toEqual([]); + }); + it('returns empty array when input does not have any duplicates', () => { + expect(findDuplicatesInArray(['A', 'B'])).toEqual([]); + }); + it('returns duplicates if input contains a duplicate', () => { + expect(findDuplicatesInArray(['A', 'B', 'A'])).toEqual(['A']); + }); + it('returns duplicates if input contains a duplicate twice', () => { + expect(findDuplicatesInArray(['A', 'B', 'A', 'A'])).toEqual(['A']); + }); + it('returns duplicates if input contains multiple duplicates', () => { + expect(findDuplicatesInArray(['A', 'B', 'A', 'B'])).toEqual(['A', 'B']); + }); + }); + describe('ensureNoDuplicatesExist', () => { + // eslint-disable-next-line jest/expect-expect + it('throws no error if everything is correct', () => { + ensureNoDuplicatesExist('Test', ['A']); + }); + it('throws error if there is a duplicate', () => { + expect(() => ensureNoDuplicatesExist('Test', ['A', 'A'])).toThrow( + "Your Test names 'A,A' contain duplicates 'A'", + ); + }); + it('throws error if there are multiple duplicates', () => { + expect(() => + ensureNoDuplicatesExist('Test', ['A', 'A', 'B', 'B']), + ).toThrow("Your Test names 'A,A,B,B' contain duplicates 'A,B'"); + }); + }); describe('toArrayConfig', () => { it('empty', () => { expect(toArrayConfig('')).toEqual(undefined); diff --git a/backend/src/config/utils.ts b/backend/src/config/utils.ts index f068f3d1d..64d897094 100644 --- a/backend/src/config/utils.ts +++ b/backend/src/config/utils.ts @@ -1,10 +1,31 @@ /* - * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ import { Loglevel } from './loglevel.enum'; +export function findDuplicatesInArray(array: T[]): T[] { + // This uses the Array-Set conversion to remove duplicates in the finding. + // This can happen if an entry is present three or more times + return Array.from( + new Set(array.filter((item, index) => array.indexOf(item) !== index)), + ); +} + +export function ensureNoDuplicatesExist( + authName: string, + names: string[], +): void { + const duplicates = findDuplicatesInArray(names); + if (duplicates.length !== 0) { + throw new Error( + `Your ${authName} names '${names.join( + ',', + )}' contain duplicates '${duplicates.join(',')}'`, + ); + } +} export function toArrayConfig( configValue?: string, separator = ',',