Add test for permission service

Many tests are generated and not static like in other files.

Signed-off-by: Yannick Bungers <git@innay.de>
This commit is contained in:
Yannick Bungers 2021-02-13 14:04:16 +01:00
parent 0ea7991e36
commit 0fc9c11a41

View file

@ -0,0 +1,526 @@
/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Test, TestingModule } from '@nestjs/testing';
import { LoggerModule } from '../logger/logger.module';
import { GuestPermission, PermissionsService } from './permissions.service';
import { User } from '../users/user.entity';
import { Note } from '../notes/note.entity';
import { UsersModule } from '../users/users.module';
import { NotesModule } from '../notes/notes.module';
import { PermissionsModule } from './permissions.module';
import { getRepositoryToken } from '@nestjs/typeorm';
import { NoteGroupPermission } from './note-group-permission.entity';
import { NoteUserPermission } from './note-user-permission.entity';
import { Identity } from '../users/identity.entity';
import { AuthToken } from '../auth/auth-token.entity';
import { Authorship } from '../revisions/authorship.entity';
import { AuthorColor } from '../notes/author-color.entity';
import { Revision } from '../revisions/revision.entity';
import { Tag } from '../notes/tag.entity';
import { Group } from '../groups/group.entity';
jest.mock('../permissions/note-group-permission.entity.ts');
jest.mock('../groups/group.entity.ts');
jest.mock('../notes/note.entity.ts');
jest.mock('../users/user.entity.ts');
describe('PermissionsService', () => {
let permissionsService: PermissionsService;
beforeAll(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [PermissionsService],
imports: [PermissionsModule, UsersModule, LoggerModule, NotesModule],
})
.overrideProvider(getRepositoryToken(User))
.useValue({})
.overrideProvider(getRepositoryToken(AuthToken))
.useValue({})
.overrideProvider(getRepositoryToken(Identity))
.useValue({})
.overrideProvider(getRepositoryToken(Authorship))
.useValue({})
.overrideProvider(getRepositoryToken(AuthorColor))
.useValue({})
.overrideProvider(getRepositoryToken(Revision))
.useValue({})
.overrideProvider(getRepositoryToken(Note))
.useValue({})
.overrideProvider(getRepositoryToken(Tag))
.useValue({})
.overrideProvider(getRepositoryToken(NoteGroupPermission))
.useValue({})
.overrideProvider(getRepositoryToken(NoteUserPermission))
.useValue({})
.compile();
permissionsService = module.get<PermissionsService>(PermissionsService);
});
// The two users we test with:
const user2 = {} as User;
user2.id = '2';
const user1 = {} as User;
user1.id = '1';
it('should be defined', () => {
expect(permissionsService).toBeDefined();
});
function createNote(owner: User): Note {
const note = {} as Note;
note.userPermissions = [];
note.groupPermissions = [];
note.owner = owner;
return note;
}
/*
* Creates the permission objects for UserPermission for two users with write and with out write permission
*/
function createNoteUserPermissionNotes(): Note[] {
const note0 = createNote(user1);
const note1 = createNote(user2);
const note2 = createNote(user2);
const note3 = createNote(user2);
const note4 = createNote(user2);
const note5 = createNote(user2);
const note6 = createNote(user2);
const note7 = createNote(user2);
const noteUserPermission1 = {} as NoteUserPermission;
noteUserPermission1.user = user1;
const noteUserPermission2 = {} as NoteUserPermission;
noteUserPermission2.user = user2;
const noteUserPermission3 = {} as NoteUserPermission;
noteUserPermission3.user = user1;
noteUserPermission3.canEdit = true;
const noteUserPermission4 = {} as NoteUserPermission;
noteUserPermission4.user = user2;
noteUserPermission4.canEdit = true;
note1.userPermissions.push(noteUserPermission1);
note2.userPermissions.push(noteUserPermission1);
note2.userPermissions.push(noteUserPermission2);
note3.userPermissions.push(noteUserPermission2);
note3.userPermissions.push(noteUserPermission1);
note4.userPermissions.push(noteUserPermission3);
note5.userPermissions.push(noteUserPermission3);
note5.userPermissions.push(noteUserPermission4);
note6.userPermissions.push(noteUserPermission4);
note6.userPermissions.push(noteUserPermission3);
note7.userPermissions.push(noteUserPermission2);
const everybody = {} as Group;
everybody.name = 'everybody';
everybody.special = true;
const noteEverybodyRead = createNote(user1);
const noteGroupPermissionRead = {} as NoteGroupPermission;
noteGroupPermissionRead.group = everybody;
noteGroupPermissionRead.canEdit = false;
noteGroupPermissionRead.note = noteEverybodyRead;
noteEverybodyRead.groupPermissions = [noteGroupPermissionRead];
const noteEverybodyWrite = createNote(user1);
const noteGroupPermissionWrite = {} as NoteGroupPermission;
noteGroupPermissionWrite.group = everybody;
noteGroupPermissionWrite.canEdit = true;
noteGroupPermissionWrite.note = noteEverybodyWrite;
noteEverybodyWrite.groupPermissions = [noteGroupPermissionWrite];
return [
note0,
note1,
note2,
note3,
note4,
note5,
note6,
note7,
noteEverybodyRead,
noteEverybodyWrite,
];
}
const notes = createNoteUserPermissionNotes();
describe('mayRead works with', () => {
it('Owner', () => {
permissionsService.guestPermission = GuestPermission.DENY;
expect(permissionsService.mayRead(user1, notes[0])).toBeTruthy();
expect(permissionsService.mayRead(user1, notes[7])).toBeFalsy();
});
it('userPermission read', () => {
permissionsService.guestPermission = GuestPermission.DENY;
expect(permissionsService.mayRead(user1, notes[1])).toBeTruthy();
expect(permissionsService.mayRead(user1, notes[2])).toBeTruthy();
expect(permissionsService.mayRead(user1, notes[3])).toBeTruthy();
});
it('userPermission write', () => {
permissionsService.guestPermission = GuestPermission.DENY;
expect(permissionsService.mayRead(user1, notes[4])).toBeTruthy();
expect(permissionsService.mayRead(user1, notes[5])).toBeTruthy();
expect(permissionsService.mayRead(user1, notes[6])).toBeTruthy();
expect(permissionsService.mayRead(user1, notes[7])).toBeFalsy();
});
describe('guest permission', () => {
it('CREATE_ALIAS', () => {
permissionsService.guestPermission = GuestPermission.CREATE_ALIAS;
expect(permissionsService.mayRead(null, notes[8])).toBeTruthy();
});
it('CREATE', () => {
permissionsService.guestPermission = GuestPermission.CREATE;
expect(permissionsService.mayRead(null, notes[8])).toBeTruthy();
});
it('WRITE', () => {
permissionsService.guestPermission = GuestPermission.WRITE;
expect(permissionsService.mayRead(null, notes[8])).toBeTruthy();
});
it('READ', () => {
permissionsService.guestPermission = GuestPermission.READ;
expect(permissionsService.mayRead(null, notes[8])).toBeTruthy();
});
});
});
describe('mayWrite works with', () => {
it('Owner', () => {
permissionsService.guestPermission = GuestPermission.DENY;
expect(permissionsService.mayWrite(user1, notes[0])).toBeTruthy();
expect(permissionsService.mayWrite(user1, notes[7])).toBeFalsy();
});
it('userPermission read', () => {
permissionsService.guestPermission = GuestPermission.DENY;
expect(permissionsService.mayWrite(user1, notes[1])).toBeFalsy();
expect(permissionsService.mayWrite(user1, notes[2])).toBeFalsy();
expect(permissionsService.mayWrite(user1, notes[3])).toBeFalsy();
});
it('userPermission write', () => {
permissionsService.guestPermission = GuestPermission.DENY;
expect(permissionsService.mayWrite(user1, notes[4])).toBeTruthy();
expect(permissionsService.mayWrite(user1, notes[5])).toBeTruthy();
expect(permissionsService.mayWrite(user1, notes[6])).toBeTruthy();
expect(permissionsService.mayWrite(user1, notes[7])).toBeFalsy();
});
describe('guest permission', () => {
it('CREATE_ALIAS', () => {
permissionsService.guestPermission = GuestPermission.CREATE_ALIAS;
expect(permissionsService.mayWrite(null, notes[9])).toBeTruthy();
});
it('CREATE', () => {
permissionsService.guestPermission = GuestPermission.CREATE;
expect(permissionsService.mayWrite(null, notes[9])).toBeTruthy();
});
it('WRITE', () => {
permissionsService.guestPermission = GuestPermission.WRITE;
expect(permissionsService.mayWrite(null, notes[9])).toBeTruthy();
});
it('READ', () => {
permissionsService.guestPermission = GuestPermission.READ;
expect(permissionsService.mayWrite(null, notes[9])).toBeFalsy();
});
});
});
/*
* Helper Object that arranges a list of GroupPermissions and if they allow a user to read or write a particular note.
*/
class NoteGroupPermissionWithResultForUser {
permissions: NoteGroupPermission[];
allowsRead: boolean;
allowsWrite: boolean;
}
/*
* Setup function to create all the groups we use in the tests.
*/
function createGroups(): { [id: string]: Group } {
const result: { [id: string]: Group } = {};
const everybody: Group = new Group();
everybody.special = true;
everybody.name = 'everybody';
result['everybody'] = everybody;
const loggedIn = new Group();
loggedIn.special = true;
loggedIn.name = 'loggedIn';
result['loggedIn'] = loggedIn;
const user1group = new Group();
user1group.name = 'user1group';
user1group.members = [user1];
result['user1group'] = user1group;
const user2group = new Group();
user2group.name = 'user2group';
user2group.members = [user2];
result['user2group'] = user2group;
const user1and2group = new Group();
user1and2group.name = 'user1and2group';
user1and2group.members = [user1, user2];
result['user1and2group'] = user1and2group;
const user2and1group = new Group();
user2and1group.name = 'user2and1group';
user2and1group.members = [user2, user1];
result['user2and1group'] = user2and1group;
return result;
}
/*
* Create all GroupPermissions: For each group two GroupPermissions are created one with read permission and one with write permission.
*/
function createAllNoteGroupPermissions(): NoteGroupPermission[][] {
const groups = createGroups();
/*
* Helper function for creating GroupPermissions
*/
function createNoteGroupPermission(
group: Group,
write: boolean,
): NoteGroupPermission {
const noteGroupPermission = new NoteGroupPermission();
noteGroupPermission.canEdit = write;
noteGroupPermission.group = group;
return noteGroupPermission;
}
const everybodyRead = createNoteGroupPermission(groups['everybody'], false);
const everybodyWrite = createNoteGroupPermission(groups['everybody'], true);
const loggedInRead = createNoteGroupPermission(groups['loggedIn'], false);
const loggedInWrite = createNoteGroupPermission(groups['loggedIn'], true);
const user1groupRead = createNoteGroupPermission(
groups['user1group'],
false,
);
const user1groupWrite = createNoteGroupPermission(
groups['user1group'],
true,
);
const user2groupRead = createNoteGroupPermission(
groups['user2group'],
false,
);
const user2groupWrite = createNoteGroupPermission(
groups['user2group'],
true,
);
const user1and2groupRead = createNoteGroupPermission(
groups['user1and2group'],
false,
);
const user1and2groupWrite = createNoteGroupPermission(
groups['user1and2group'],
true,
);
const user2and1groupRead = createNoteGroupPermission(
groups['user2and1group'],
false,
);
const user2and1groupWrite = createNoteGroupPermission(
groups['user2and1group'],
true,
);
return [
[user1groupRead, user1and2groupRead, user2and1groupRead, null], // group0: allow user1 to read via group
[user2and1groupWrite, user1and2groupWrite, user1groupWrite, null], // group1: allow user1 to write via group
[everybodyRead, everybodyWrite, null], // group2: permissions of the special group everybody
[loggedInRead, loggedInWrite, null], // group3: permissions of the special group loggedIn
[user2groupWrite, user2groupRead, null], // group4: don't allow user1 to read or write via group
];
}
/*
* creates the matrix multiplication of group0 to group4 of createAllNoteGroupPermissions
*/
function createNoteGroupPermissionsCombinations(
guestPermission: GuestPermission,
): NoteGroupPermissionWithResultForUser[] {
// for logged in users
const noteGroupPermissions = createAllNoteGroupPermissions();
const result: NoteGroupPermissionWithResultForUser[] = [];
for (const group0 of noteGroupPermissions[0]) {
for (const group1 of noteGroupPermissions[1]) {
for (const group2 of noteGroupPermissions[2]) {
for (const group3 of noteGroupPermissions[3]) {
for (const group4 of noteGroupPermissions[4]) {
const insert = [];
let readPermission = false;
let writePermission = false;
if (group0 !== null) {
// user1 in ReadGroups
readPermission = true;
insert.push(group0);
}
if (group1 !== null) {
// user1 in WriteGroups
readPermission = true;
writePermission = true;
insert.push(group1);
}
if (group2 !== null) {
// everybody group TODO config options
switch (guestPermission) {
case GuestPermission.CREATE_ALIAS:
case GuestPermission.CREATE:
case GuestPermission.WRITE:
writePermission = writePermission || group2.canEdit;
readPermission = true;
break;
case GuestPermission.READ:
readPermission = true;
}
insert.push(group2);
}
if (group3 !== null) {
// loggedIn users
readPermission = true;
writePermission = writePermission || group3.canEdit;
insert.push(group3);
}
if (group4 !== null) {
// user not in group
insert.push(group4);
}
result.push({
permissions: insert,
allowsRead: readPermission,
allowsWrite: writePermission,
});
}
}
}
}
}
return result;
}
// inspired by https://stackoverflow.com/questions/9960908/permutations-in-javascript
function permutator(
inputArr: NoteGroupPermission[],
): NoteGroupPermission[][] {
const results = [];
function permute(arr, memo) {
let cur;
for (let i = 0; i < arr.length; i++) {
cur = arr.splice(i, 1);
if (arr.length === 0) {
results.push(memo.concat(cur));
}
permute(arr.slice(), memo.concat(cur));
arr.splice(i, 0, cur[0]);
}
return results;
}
return permute(inputArr, []);
}
// takes each set of permissions from createNoteGroupPermissionsCombinations, permute them and add them to the list
function permuteNoteGroupPermissions(
noteGroupPermissions: NoteGroupPermissionWithResultForUser[],
): NoteGroupPermissionWithResultForUser[] {
const result: NoteGroupPermissionWithResultForUser[] = [];
for (const permission of noteGroupPermissions) {
const permutations = permutator(permission.permissions);
for (const permutation of permutations) {
result.push({
permissions: permutation,
allowsRead: permission.allowsRead,
allowsWrite: permission.allowsWrite,
});
}
}
return result;
}
describe('check if groups work with', () => {
const guestPermission = GuestPermission.WRITE;
const rawPermissions = createNoteGroupPermissionsCombinations(
guestPermission,
);
const permissions = permuteNoteGroupPermissions(rawPermissions);
let i = 0;
for (const permission of permissions) {
const note = createNote(user2);
note.groupPermissions = permission.permissions;
let permissionString = '';
for (const perm of permission.permissions) {
permissionString += ' ' + perm.group.name + ':' + perm.canEdit;
}
it('mayWrite - test #' + i + ':' + permissionString, () => {
permissionsService.guestPermission = guestPermission;
expect(permissionsService.mayWrite(user1, note)).toEqual(
permission.allowsWrite,
);
});
it('mayRead - test #' + i + ':' + permissionString, () => {
permissionsService.guestPermission = guestPermission;
expect(permissionsService.mayRead(user1, note)).toEqual(
permission.allowsRead,
);
});
i++;
}
});
describe('mayCreate works for', () => {
it('logged in', () => {
permissionsService.guestPermission = GuestPermission.DENY;
expect(permissionsService.mayCreate(user1)).toBeTruthy();
});
it('guest denied', () => {
permissionsService.guestPermission = GuestPermission.DENY;
expect(permissionsService.mayCreate(null)).toBeFalsy();
});
it('guest read', () => {
permissionsService.guestPermission = GuestPermission.READ;
expect(permissionsService.mayCreate(null)).toBeFalsy();
});
it('guest write', () => {
permissionsService.guestPermission = GuestPermission.WRITE;
expect(permissionsService.mayCreate(null)).toBeFalsy();
});
it('guest create', () => {
permissionsService.guestPermission = GuestPermission.CREATE;
expect(permissionsService.mayCreate(null)).toBeTruthy();
});
it('guest create alias', () => {
permissionsService.guestPermission = GuestPermission.CREATE_ALIAS;
expect(permissionsService.mayCreate(null)).toBeTruthy();
});
});
describe('isOwner works', () => {
it('for positive case', () => {
permissionsService.guestPermission = GuestPermission.DENY;
expect(permissionsService.isOwner(user1, notes[0])).toBeTruthy();
});
it('for negative case', () => {
permissionsService.guestPermission = GuestPermission.DENY;
expect(permissionsService.isOwner(user1, notes[1])).toBeFalsy();
});
});
});