mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-29 06:15:29 -04:00
feat(config): add config vars for default permissions for special groups
Co-authored-by: Tilman Vatteroth <git@tilmanvatteroth.de> Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de> Signed-off-by: Philip Molares <philip.molares@udo.edu>
This commit is contained in:
parent
7dd093a44f
commit
df976b5fe1
10 changed files with 518 additions and 36 deletions
26
src/config/default-access-permission.enum.ts
Normal file
26
src/config/default-access-permission.enum.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export enum DefaultAccessPermission {
|
||||
NONE = 'none',
|
||||
READ = 'read',
|
||||
WRITE = 'write',
|
||||
}
|
||||
|
||||
export function getDefaultAccessPermissionOrdinal(
|
||||
permission: DefaultAccessPermission,
|
||||
): number {
|
||||
switch (permission) {
|
||||
case DefaultAccessPermission.NONE:
|
||||
return 0;
|
||||
case DefaultAccessPermission.READ:
|
||||
return 1;
|
||||
case DefaultAccessPermission.WRITE:
|
||||
return 2;
|
||||
default:
|
||||
throw Error('Unknown permission');
|
||||
}
|
||||
}
|
29
src/config/guest_access.enum.ts
Normal file
29
src/config/guest_access.enum.ts
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export enum GuestAccess {
|
||||
DENY = 'deny',
|
||||
READ = 'read',
|
||||
WRITE = 'write',
|
||||
CREATE = 'create',
|
||||
}
|
||||
|
||||
export function getGuestAccessOrdinal(
|
||||
guestAccess: GuestAccess,
|
||||
): number {
|
||||
switch (guestAccess) {
|
||||
case GuestAccess.DENY:
|
||||
return 0;
|
||||
case GuestAccess.READ:
|
||||
return 1;
|
||||
case GuestAccess.WRITE:
|
||||
return 2;
|
||||
case GuestAccess.CREATE:
|
||||
return 3;
|
||||
default:
|
||||
throw Error('Unknown permission');
|
||||
}
|
||||
}
|
|
@ -6,12 +6,21 @@
|
|||
import { ConfigFactoryKeyHost, registerAs } from '@nestjs/config';
|
||||
import { ConfigFactory } from '@nestjs/config/dist/interfaces';
|
||||
|
||||
import { DefaultAccessPermission } from '../default-access-permission.enum';
|
||||
import { DefaultAccessPermission } from '../default-access-permission.enum';
|
||||
import { NoteConfig } from '../note.config';
|
||||
import { GuestAccess } from '../guest_access.enum';
|
||||
|
||||
export function createDefaultMockNoteConfig(): NoteConfig {
|
||||
return {
|
||||
maxDocumentLength: 100000,
|
||||
forbiddenNoteIds: ['forbiddenNoteId'],
|
||||
permissions: {
|
||||
default: {
|
||||
everyone: DefaultAccessPermission.READ,
|
||||
loggedIn: DefaultAccessPermission.WRITE,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
*/
|
||||
import mockedEnv from 'mocked-env';
|
||||
|
||||
import { DefaultAccessPermission } from './default-access-permission.enum';
|
||||
import { GuestAccess } from './guest_access.enum';
|
||||
import noteConfig from './note.config';
|
||||
|
||||
describe('noteConfig', () => {
|
||||
|
@ -15,14 +17,19 @@ describe('noteConfig', () => {
|
|||
const negativeMaxDocumentLength = -123;
|
||||
const floatMaxDocumentLength = 2.71;
|
||||
const invalidMaxDocumentLength = 'not-a-max-document-length';
|
||||
const guestAccess = GuestAccess.CREATE;
|
||||
const wrongDefaultPermission = 'wrong';
|
||||
|
||||
describe('correctly parses config', () => {
|
||||
it('when given correct and complete environment variables', async () => {
|
||||
it('when given correct and complete environment variables', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_FORBIDDEN_NOTE_IDS: forbiddenNoteIds.join(' , '),
|
||||
HD_MAX_DOCUMENT_LENGTH: maxDocumentLength.toString(),
|
||||
HD_PERMISSION_DEFAULT_EVERYONE: DefaultAccessPermission.READ,
|
||||
HD_PERMISSION_DEFAULT_LOGGED_IN: DefaultAccessPermission.READ,
|
||||
HD_GUEST_ACCESS: guestAccess,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
|
@ -33,6 +40,13 @@ describe('noteConfig', () => {
|
|||
expect(config.forbiddenNoteIds).toHaveLength(forbiddenNoteIds.length);
|
||||
expect(config.forbiddenNoteIds).toEqual(forbiddenNoteIds);
|
||||
expect(config.maxDocumentLength).toEqual(maxDocumentLength);
|
||||
expect(config.permissions.default.everyone).toEqual(
|
||||
DefaultAccessPermission.READ,
|
||||
);
|
||||
expect(config.permissions.default.loggedIn).toEqual(
|
||||
DefaultAccessPermission.READ,
|
||||
);
|
||||
expect(config.guestAccess).toEqual(guestAccess);
|
||||
restore();
|
||||
});
|
||||
|
||||
|
@ -41,6 +55,9 @@ describe('noteConfig', () => {
|
|||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_MAX_DOCUMENT_LENGTH: maxDocumentLength.toString(),
|
||||
HD_PERMISSION_DEFAULT_EVERYONE: DefaultAccessPermission.READ,
|
||||
HD_PERMISSION_DEFAULT_LOGGED_IN: DefaultAccessPermission.READ,
|
||||
HD_GUEST_ACCESS: guestAccess,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
|
@ -50,24 +67,13 @@ describe('noteConfig', () => {
|
|||
const config = noteConfig();
|
||||
expect(config.forbiddenNoteIds).toHaveLength(0);
|
||||
expect(config.maxDocumentLength).toEqual(maxDocumentLength);
|
||||
restore();
|
||||
});
|
||||
|
||||
it('when no HD_MAX_DOCUMENT_LENGTH is set', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_FORBIDDEN_NOTE_IDS: forbiddenNoteIds.join(' , '),
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
},
|
||||
expect(config.permissions.default.everyone).toEqual(
|
||||
DefaultAccessPermission.READ,
|
||||
);
|
||||
const config = noteConfig();
|
||||
expect(config.forbiddenNoteIds).toHaveLength(forbiddenNoteIds.length);
|
||||
expect(config.forbiddenNoteIds).toEqual(forbiddenNoteIds);
|
||||
expect(config.maxDocumentLength).toEqual(100000);
|
||||
expect(config.permissions.default.loggedIn).toEqual(
|
||||
DefaultAccessPermission.READ,
|
||||
);
|
||||
expect(config.guestAccess).toEqual(guestAccess);
|
||||
restore();
|
||||
});
|
||||
|
||||
|
@ -77,6 +83,9 @@ describe('noteConfig', () => {
|
|||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_FORBIDDEN_NOTE_IDS: forbiddenNoteId,
|
||||
HD_MAX_DOCUMENT_LENGTH: maxDocumentLength.toString(),
|
||||
HD_PERMISSION_DEFAULT_EVERYONE: DefaultAccessPermission.READ,
|
||||
HD_PERMISSION_DEFAULT_LOGGED_IN: DefaultAccessPermission.READ,
|
||||
HD_GUEST_ACCESS: guestAccess,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
|
@ -87,9 +96,133 @@ describe('noteConfig', () => {
|
|||
expect(config.forbiddenNoteIds).toHaveLength(1);
|
||||
expect(config.forbiddenNoteIds[0]).toEqual(forbiddenNoteId);
|
||||
expect(config.maxDocumentLength).toEqual(maxDocumentLength);
|
||||
expect(config.permissions.default.everyone).toEqual(
|
||||
DefaultAccessPermission.READ,
|
||||
);
|
||||
expect(config.permissions.default.loggedIn).toEqual(
|
||||
DefaultAccessPermission.READ,
|
||||
);
|
||||
|
||||
expect(config.guestAccess).toEqual(guestAccess);
|
||||
restore();
|
||||
});
|
||||
|
||||
it('when no HD_MAX_DOCUMENT_LENGTH is set', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_FORBIDDEN_NOTE_IDS: forbiddenNoteIds.join(' , '),
|
||||
HD_PERMISSION_DEFAULT_EVERYONE: DefaultAccessPermission.READ,
|
||||
HD_PERMISSION_DEFAULT_LOGGED_IN: DefaultAccessPermission.READ,
|
||||
HD_GUEST_ACCESS: guestAccess,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
},
|
||||
);
|
||||
const config = noteConfig();
|
||||
expect(config.forbiddenNoteIds).toHaveLength(forbiddenNoteIds.length);
|
||||
expect(config.forbiddenNoteIds).toEqual(forbiddenNoteIds);
|
||||
expect(config.maxDocumentLength).toEqual(100000);
|
||||
expect(config.permissions.default.everyone).toEqual(
|
||||
DefaultAccessPermission.READ,
|
||||
);
|
||||
expect(config.permissions.default.loggedIn).toEqual(
|
||||
DefaultAccessPermission.READ,
|
||||
);
|
||||
|
||||
expect(config.guestAccess).toEqual(guestAccess);
|
||||
restore();
|
||||
});
|
||||
|
||||
it('when no HD_PERMISSION_DEFAULT_EVERYONE is set', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_FORBIDDEN_NOTE_IDS: forbiddenNoteIds.join(' , '),
|
||||
HD_MAX_DOCUMENT_LENGTH: maxDocumentLength.toString(),
|
||||
HD_PERMISSION_DEFAULT_LOGGED_IN: DefaultAccessPermission.READ,
|
||||
HD_GUEST_ACCESS: guestAccess,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
},
|
||||
);
|
||||
const config = noteConfig();
|
||||
expect(config.forbiddenNoteIds).toHaveLength(forbiddenNoteIds.length);
|
||||
expect(config.forbiddenNoteIds).toEqual(forbiddenNoteIds);
|
||||
expect(config.maxDocumentLength).toEqual(maxDocumentLength);
|
||||
expect(config.permissions.default.everyone).toEqual(
|
||||
DefaultAccessPermission.READ,
|
||||
);
|
||||
expect(config.permissions.default.loggedIn).toEqual(
|
||||
DefaultAccessPermission.READ,
|
||||
);
|
||||
|
||||
expect(config.guestAccess).toEqual(guestAccess);
|
||||
restore();
|
||||
});
|
||||
|
||||
it('when no HD_PERMISSION_DEFAULT_LOGGED_IN is set', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_FORBIDDEN_NOTE_IDS: forbiddenNoteIds.join(' , '),
|
||||
HD_MAX_DOCUMENT_LENGTH: maxDocumentLength.toString(),
|
||||
HD_PERMISSION_DEFAULT_EVERYONE: DefaultAccessPermission.READ,
|
||||
HD_GUEST_ACCESS: guestAccess,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
},
|
||||
);
|
||||
const config = noteConfig();
|
||||
expect(config.forbiddenNoteIds).toHaveLength(forbiddenNoteIds.length);
|
||||
expect(config.forbiddenNoteIds).toEqual(forbiddenNoteIds);
|
||||
expect(config.maxDocumentLength).toEqual(maxDocumentLength);
|
||||
expect(config.permissions.default.everyone).toEqual(
|
||||
DefaultAccessPermission.READ,
|
||||
);
|
||||
expect(config.permissions.default.loggedIn).toEqual(
|
||||
DefaultAccessPermission.WRITE,
|
||||
);
|
||||
|
||||
expect(config.guestAccess).toEqual(guestAccess);
|
||||
restore();
|
||||
});
|
||||
|
||||
it('when no HD_GUEST_ACCESS is set', () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_FORBIDDEN_NOTE_IDS: forbiddenNoteIds.join(' , '),
|
||||
HD_MAX_DOCUMENT_LENGTH: maxDocumentLength.toString(),
|
||||
HD_PERMISSION_DEFAULT_EVERYONE: DefaultAccessPermission.READ,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
},
|
||||
);
|
||||
const config = noteConfig();
|
||||
expect(config.forbiddenNoteIds).toHaveLength(forbiddenNoteIds.length);
|
||||
expect(config.forbiddenNoteIds).toEqual(forbiddenNoteIds);
|
||||
expect(config.maxDocumentLength).toEqual(maxDocumentLength);
|
||||
expect(config.permissions.default.everyone).toEqual(
|
||||
DefaultAccessPermission.READ,
|
||||
);
|
||||
expect(config.permissions.default.loggedIn).toEqual(
|
||||
DefaultAccessPermission.WRITE,
|
||||
);
|
||||
|
||||
expect(config.guestAccess).toEqual(GuestAccess.WRITE);
|
||||
restore();
|
||||
});
|
||||
});
|
||||
|
||||
describe('throws error', () => {
|
||||
it('when given a non-valid HD_FORBIDDEN_NOTE_IDS', async () => {
|
||||
const restore = mockedEnv(
|
||||
|
@ -97,6 +230,9 @@ describe('noteConfig', () => {
|
|||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_FORBIDDEN_NOTE_IDS: invalidforbiddenNoteIds.join(' , '),
|
||||
HD_MAX_DOCUMENT_LENGTH: maxDocumentLength.toString(),
|
||||
HD_PERMISSION_DEFAULT_EVERYONE: DefaultAccessPermission.READ,
|
||||
HD_PERMISSION_DEFAULT_LOGGED_IN: DefaultAccessPermission.READ,
|
||||
HD_GUEST_ACCESS: guestAccess,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
|
@ -115,6 +251,9 @@ describe('noteConfig', () => {
|
|||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_FORBIDDEN_NOTE_IDS: forbiddenNoteIds.join(' , '),
|
||||
HD_MAX_DOCUMENT_LENGTH: negativeMaxDocumentLength.toString(),
|
||||
HD_PERMISSION_DEFAULT_EVERYONE: DefaultAccessPermission.READ,
|
||||
HD_PERMISSION_DEFAULT_LOGGED_IN: DefaultAccessPermission.READ,
|
||||
HD_GUEST_ACCESS: guestAccess,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
|
@ -133,6 +272,9 @@ describe('noteConfig', () => {
|
|||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_FORBIDDEN_NOTE_IDS: forbiddenNoteIds.join(' , '),
|
||||
HD_MAX_DOCUMENT_LENGTH: floatMaxDocumentLength.toString(),
|
||||
HD_PERMISSION_DEFAULT_EVERYONE: DefaultAccessPermission.READ,
|
||||
HD_PERMISSION_DEFAULT_LOGGED_IN: DefaultAccessPermission.READ,
|
||||
HD_GUEST_ACCESS: guestAccess,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
|
@ -151,6 +293,9 @@ describe('noteConfig', () => {
|
|||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_FORBIDDEN_NOTE_IDS: forbiddenNoteIds.join(' , '),
|
||||
HD_MAX_DOCUMENT_LENGTH: invalidMaxDocumentLength,
|
||||
HD_PERMISSION_DEFAULT_EVERYONE: DefaultAccessPermission.READ,
|
||||
HD_PERMISSION_DEFAULT_LOGGED_IN: DefaultAccessPermission.READ,
|
||||
HD_GUEST_ACCESS: guestAccess,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
|
@ -162,5 +307,152 @@ describe('noteConfig', () => {
|
|||
);
|
||||
restore();
|
||||
});
|
||||
|
||||
it('when given a non-valid HD_PERMISSION_DEFAULT_EVERYONE', async () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_FORBIDDEN_NOTE_IDS: forbiddenNoteIds.join(' , '),
|
||||
HD_MAX_DOCUMENT_LENGTH: maxDocumentLength.toString(),
|
||||
HD_PERMISSION_DEFAULT_EVERYONE: wrongDefaultPermission,
|
||||
HD_PERMISSION_DEFAULT_LOGGED_IN: DefaultAccessPermission.READ,
|
||||
HD_GUEST_ACCESS: guestAccess,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
},
|
||||
);
|
||||
expect(() => noteConfig()).toThrow(
|
||||
'"HD_PERMISSION_DEFAULT_EVERYONE" must be one of [none, read, write]',
|
||||
);
|
||||
restore();
|
||||
});
|
||||
|
||||
it('when given a non-valid HD_PERMISSION_DEFAULT_LOGGED_IN', async () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_FORBIDDEN_NOTE_IDS: forbiddenNoteIds.join(' , '),
|
||||
HD_MAX_DOCUMENT_LENGTH: maxDocumentLength.toString(),
|
||||
HD_PERMISSION_DEFAULT_EVERYONE: DefaultAccessPermission.READ,
|
||||
HD_PERMISSION_DEFAULT_LOGGED_IN: wrongDefaultPermission,
|
||||
HD_GUEST_ACCESS: guestAccess,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
},
|
||||
);
|
||||
expect(() => noteConfig()).toThrow(
|
||||
'"HD_PERMISSION_DEFAULT_LOGGED_IN" must be one of [none, read, write]',
|
||||
);
|
||||
restore();
|
||||
});
|
||||
|
||||
it('when given a non-valid HD_GUEST_ACCESS', async () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_FORBIDDEN_NOTE_IDS: forbiddenNoteIds.join(' , '),
|
||||
HD_MAX_DOCUMENT_LENGTH: maxDocumentLength.toString(),
|
||||
HD_PERMISSION_DEFAULT_EVERYONE: DefaultAccessPermission.READ,
|
||||
HD_PERMISSION_DEFAULT_LOGGED_IN: DefaultAccessPermission.READ,
|
||||
HD_GUEST_ACCESS: wrongDefaultPermission,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
},
|
||||
);
|
||||
expect(() => noteConfig()).toThrow(
|
||||
'"HD_GUEST_ACCESS" must be one of [deny, read, write, create]',
|
||||
);
|
||||
restore();
|
||||
});
|
||||
|
||||
it('when HD_GUEST_ACCESS is set to deny and HD_PERMISSION_DEFAULT_EVERYONE is set', async () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_FORBIDDEN_NOTE_IDS: forbiddenNoteIds.join(' , '),
|
||||
HD_MAX_DOCUMENT_LENGTH: maxDocumentLength.toString(),
|
||||
HD_PERMISSION_DEFAULT_EVERYONE: DefaultAccessPermission.READ,
|
||||
HD_PERMISSION_DEFAULT_LOGGED_IN: DefaultAccessPermission.READ,
|
||||
HD_GUEST_ACCESS: 'deny',
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
},
|
||||
);
|
||||
expect(() => noteConfig()).toThrow(
|
||||
`'HD_GUEST_ACCESS' is set to 'deny', but 'HD_PERMISSION_DEFAULT_EVERYONE' is also configured. Please remove 'HD_PERMISSION_DEFAULT_EVERYONE'.`,
|
||||
);
|
||||
restore();
|
||||
});
|
||||
|
||||
it('when HD_PERMISSION_DEFAULT_EVERYONE is set to write, but HD_PERMISSION_DEFAULT_LOGGED_IN is set to read', async () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_FORBIDDEN_NOTE_IDS: forbiddenNoteIds.join(' , '),
|
||||
HD_MAX_DOCUMENT_LENGTH: maxDocumentLength.toString(),
|
||||
HD_PERMISSION_DEFAULT_EVERYONE: DefaultAccessPermission.WRITE,
|
||||
HD_PERMISSION_DEFAULT_LOGGED_IN: DefaultAccessPermission.READ,
|
||||
HD_GUEST_ACCESS: guestAccess,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
},
|
||||
);
|
||||
expect(() => noteConfig()).toThrow(
|
||||
`'HD_PERMISSION_DEFAULT_EVERYONE' is set to '${DefaultAccessPermission.WRITE}', but 'HD_PERMISSION_DEFAULT_LOGGED_IN' is set to '${DefaultAccessPermission.READ}'. This gives everyone greater permissions than logged-in users which is not allowed.`,
|
||||
);
|
||||
restore();
|
||||
});
|
||||
|
||||
it('when HD_PERMISSION_DEFAULT_EVERYONE is set to write, but HD_PERMISSION_DEFAULT_LOGGED_IN is set to none', async () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_FORBIDDEN_NOTE_IDS: forbiddenNoteIds.join(' , '),
|
||||
HD_MAX_DOCUMENT_LENGTH: maxDocumentLength.toString(),
|
||||
HD_PERMISSION_DEFAULT_EVERYONE: DefaultAccessPermission.WRITE,
|
||||
HD_PERMISSION_DEFAULT_LOGGED_IN: DefaultAccessPermission.NONE,
|
||||
HD_GUEST_ACCESS: guestAccess,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
},
|
||||
);
|
||||
expect(() => noteConfig()).toThrow(
|
||||
`'HD_PERMISSION_DEFAULT_EVERYONE' is set to '${DefaultAccessPermission.WRITE}', but 'HD_PERMISSION_DEFAULT_LOGGED_IN' is set to '${DefaultAccessPermission.NONE}'. This gives everyone greater permissions than logged-in users which is not allowed.`,
|
||||
);
|
||||
restore();
|
||||
});
|
||||
|
||||
it('when HD_PERMISSION_DEFAULT_EVERYONE is set to read, but HD_PERMISSION_DEFAULT_LOGGED_IN is set to none', async () => {
|
||||
const restore = mockedEnv(
|
||||
{
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
HD_FORBIDDEN_NOTE_IDS: forbiddenNoteIds.join(' , '),
|
||||
HD_MAX_DOCUMENT_LENGTH: maxDocumentLength.toString(),
|
||||
HD_PERMISSION_DEFAULT_EVERYONE: DefaultAccessPermission.READ,
|
||||
HD_PERMISSION_DEFAULT_LOGGED_IN: DefaultAccessPermission.NONE,
|
||||
HD_GUEST_ACCESS: guestAccess,
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
},
|
||||
{
|
||||
clear: true,
|
||||
},
|
||||
);
|
||||
expect(() => noteConfig()).toThrow(
|
||||
`'HD_PERMISSION_DEFAULT_EVERYONE' is set to '${DefaultAccessPermission.READ}', but 'HD_PERMISSION_DEFAULT_LOGGED_IN' is set to '${DefaultAccessPermission.NONE}'. This gives everyone greater permissions than logged-in users which is not allowed.`,
|
||||
);
|
||||
restore();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,14 +6,26 @@
|
|||
import { registerAs } from '@nestjs/config';
|
||||
import * as Joi from 'joi';
|
||||
|
||||
import {
|
||||
DefaultAccessPermission,
|
||||
getDefaultAccessPermissionOrdinal,
|
||||
} from './default-access-permission.enum';
|
||||
import { GuestAccess } from './guest_access.enum';
|
||||
import { buildErrorMessage, parseOptionalNumber, toArrayConfig } from './utils';
|
||||
|
||||
export interface NoteConfig {
|
||||
forbiddenNoteIds: string[];
|
||||
maxDocumentLength: number;
|
||||
guestAccess: GuestAccess;
|
||||
permissions: {
|
||||
default: {
|
||||
everyone: DefaultAccessPermission;
|
||||
loggedIn: DefaultAccessPermission;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const schema = Joi.object({
|
||||
const schema = Joi.object<NoteConfig>({
|
||||
forbiddenNoteIds: Joi.array()
|
||||
.items(Joi.string())
|
||||
.optional()
|
||||
|
@ -25,8 +37,52 @@ const schema = Joi.object({
|
|||
.integer()
|
||||
.optional()
|
||||
.label('HD_MAX_DOCUMENT_LENGTH'),
|
||||
guestAccess: Joi.string()
|
||||
.valid(...Object.values(GuestAccess))
|
||||
.optional()
|
||||
.default(GuestAccess.WRITE)
|
||||
.label('HD_GUEST_ACCESS'),
|
||||
permissions: {
|
||||
default: {
|
||||
everyone: Joi.string()
|
||||
.valid(...Object.values(DefaultAccessPermission))
|
||||
.optional()
|
||||
.default(DefaultAccessPermission.READ)
|
||||
.label('HD_PERMISSION_DEFAULT_EVERYONE'),
|
||||
loggedIn: Joi.string()
|
||||
.valid(...Object.values(DefaultAccessPermission))
|
||||
.optional()
|
||||
.default(DefaultAccessPermission.WRITE)
|
||||
.label('HD_PERMISSION_DEFAULT_LOGGED_IN'),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
function checkEveryoneConfigIsConsistent(config: NoteConfig): void {
|
||||
const everyoneDefaultSet =
|
||||
process.env.HD_PERMISSION_DEFAULT_EVERYONE !== undefined;
|
||||
if (config.guestAccess === GuestAccess.DENY && everyoneDefaultSet) {
|
||||
throw new Error(
|
||||
`'HD_GUEST_ACCESS' is set to '${config.guestAccess}', but 'HD_PERMISSION_DEFAULT_EVERYONE' is also configured. Please remove 'HD_PERMISSION_DEFAULT_EVERYONE'.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function checkLoggedInUsersHaveHigherDefaultPermissionsThanGuests(
|
||||
config: NoteConfig,
|
||||
): void {
|
||||
const everyone = config.permissions.default.everyone;
|
||||
const loggedIn = config.permissions.default.loggedIn;
|
||||
if (
|
||||
getDefaultAccessPermissionOrdinal(everyone) >
|
||||
getDefaultAccessPermissionOrdinal(loggedIn)
|
||||
) {
|
||||
throw new Error(
|
||||
`'HD_PERMISSION_DEFAULT_EVERYONE' is set to '${everyone}', but 'HD_PERMISSION_DEFAULT_LOGGED_IN' is set to '${loggedIn}'. This gives everyone greater permissions than logged-in users which is not allowed.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default registerAs('noteConfig', () => {
|
||||
const noteConfig = schema.validate(
|
||||
{
|
||||
|
@ -34,7 +90,14 @@ export default registerAs('noteConfig', () => {
|
|||
maxDocumentLength: parseOptionalNumber(
|
||||
process.env.HD_MAX_DOCUMENT_LENGTH,
|
||||
),
|
||||
},
|
||||
guestAccess: process.env.HD_GUEST_ACCESS,
|
||||
permissions: {
|
||||
default: {
|
||||
everyone: process.env.HD_PERMISSION_DEFAULT_EVERYONE,
|
||||
loggedIn: process.env.HD_PERMISSION_DEFAULT_LOGGED_IN,
|
||||
},
|
||||
},
|
||||
} as NoteConfig,
|
||||
{
|
||||
abortEarly: false,
|
||||
presence: 'required',
|
||||
|
@ -46,5 +109,8 @@ export default registerAs('noteConfig', () => {
|
|||
);
|
||||
throw new Error(buildErrorMessage(errorMessages));
|
||||
}
|
||||
return noteConfig.value as NoteConfig;
|
||||
const config = noteConfig.value;
|
||||
checkEveryoneConfigIsConsistent(config);
|
||||
checkLoggedInUsersHaveHigherDefaultPermissionsThanGuests(config);
|
||||
return config;
|
||||
});
|
||||
|
|
|
@ -10,6 +10,7 @@ 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 { Loglevel } from '../config/loglevel.enum';
|
||||
|
@ -191,7 +192,14 @@ describe('FrontendConfigService', () => {
|
|||
return {
|
||||
forbiddenNoteIds: [],
|
||||
maxDocumentLength: 200,
|
||||
};
|
||||
guestAccess: true,
|
||||
permissions: {
|
||||
default: {
|
||||
everyone: DefaultAccessPermission.READ,
|
||||
loggedIn: DefaultAccessPermission.WRITE,
|
||||
},
|
||||
},
|
||||
} as NoteConfig;
|
||||
}),
|
||||
],
|
||||
}),
|
||||
|
@ -350,6 +358,13 @@ describe('FrontendConfigService', () => {
|
|||
const noteConfig: NoteConfig = {
|
||||
forbiddenNoteIds: [],
|
||||
maxDocumentLength: maxDocumentLength,
|
||||
guestAccess: true,
|
||||
permissions: {
|
||||
default: {
|
||||
everyone: DefaultAccessPermission.READ,
|
||||
loggedIn: DefaultAccessPermission.WRITE,
|
||||
},
|
||||
},
|
||||
};
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
imports: [
|
||||
|
@ -377,8 +392,7 @@ describe('FrontendConfigService', () => {
|
|||
const service = module.get(FrontendConfigService);
|
||||
const config = await service.getFrontendConfig();
|
||||
expect(config.allowRegister).toEqual(enableRegister);
|
||||
|
||||
expect(config.allowAnonymous).toEqual(false);
|
||||
expect(config.allowAnonymous).toEqual(noteConfig.guestAccess);
|
||||
expect(config.branding.name).toEqual(customName);
|
||||
expect(config.branding.logo).toEqual(
|
||||
customLogo ? new URL(customLogo) : undefined,
|
||||
|
|
|
@ -46,8 +46,7 @@ export class FrontendConfigService {
|
|||
|
||||
async getFrontendConfig(): Promise<FrontendConfigDto> {
|
||||
return {
|
||||
// ToDo: use actual value here
|
||||
allowAnonymous: false,
|
||||
allowAnonymous: this.noteConfig.guestAccess,
|
||||
allowRegister: this.authConfig.local.enableRegister,
|
||||
authProviders: this.getAuthProviders(),
|
||||
branding: this.getBranding(),
|
||||
|
|
|
@ -96,6 +96,26 @@ export class NotesService {
|
|||
HistoryEntry.create(owner, newNote as Note) as HistoryEntry,
|
||||
]);
|
||||
}
|
||||
|
||||
const everyonePermission = this.createGroupPermission(
|
||||
newNote as Note,
|
||||
await this.groupsService.getEveryoneGroup(),
|
||||
owner === null
|
||||
? DefaultAccessPermission.WRITE
|
||||
: this.noteConfig.permissions.default.everyone,
|
||||
);
|
||||
|
||||
const loggedInPermission = this.createGroupPermission(
|
||||
newNote as Note,
|
||||
await this.groupsService.getLoggedInGroup(),
|
||||
this.noteConfig.permissions.default.loggedIn,
|
||||
);
|
||||
|
||||
newNote.groupPermissions = Promise.resolve([
|
||||
...Optional.ofNullable(everyonePermission).wrapInArray(),
|
||||
...Optional.ofNullable(loggedInPermission).wrapInArray(),
|
||||
]);
|
||||
|
||||
try {
|
||||
return await this.noteRepository.save(newNote);
|
||||
} catch (e) {
|
||||
|
@ -113,6 +133,20 @@ export class NotesService {
|
|||
}
|
||||
}
|
||||
|
||||
private createGroupPermission(
|
||||
note: Note,
|
||||
group: Group,
|
||||
permission: DefaultAccessPermission,
|
||||
): NoteGroupPermission | null {
|
||||
return permission === DefaultAccessPermission.NONE
|
||||
? null
|
||||
: NoteGroupPermission.create(
|
||||
group,
|
||||
note,
|
||||
permission === DefaultAccessPermission.WRITE,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @async
|
||||
* Get the current content of the note.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue