fix(security): Befunde aus dem Security-Audit beheben #7
No files matched your search
@@ -0,0 +1,45 @@
|
|||||||
|
import { Permission } from '../auth/permissions.enum';
|
||||||
|
import {
|
||||||
|
POSTEINGANG_TAG_ID,
|
||||||
|
darfDokumentBearbeiten,
|
||||||
|
} from './dokument-zugriff.util';
|
||||||
|
|
||||||
|
const MANUELL = 6;
|
||||||
|
|
||||||
|
describe('darfDokumentBearbeiten', () => {
|
||||||
|
it('Posteingang-Rolle: nur Dokumente mit Posteingang-Tag', () => {
|
||||||
|
const rechte = [Permission.VIEW_INBOX];
|
||||||
|
expect(
|
||||||
|
darfDokumentBearbeiten([POSTEINGANG_TAG_ID, 9], rechte, MANUELL),
|
||||||
|
).toBe(true);
|
||||||
|
expect(darfDokumentBearbeiten([9], rechte, MANUELL)).toBe(false);
|
||||||
|
expect(darfDokumentBearbeiten([MANUELL], rechte, MANUELL)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Buchhaltung: Dokumente mit Manuell-Tag', () => {
|
||||||
|
const rechte = [Permission.PROCESS_MANUALLY];
|
||||||
|
expect(darfDokumentBearbeiten([MANUELL], rechte, MANUELL)).toBe(true);
|
||||||
|
expect(darfDokumentBearbeiten([POSTEINGANG_TAG_ID], rechte, MANUELL)).toBe(
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Admins dürfen alles', () => {
|
||||||
|
expect(darfDokumentBearbeiten([], [Permission.MANAGE_ALL], MANUELL)).toBe(
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('andere Rollen und fehlende Tags: nein', () => {
|
||||||
|
expect(
|
||||||
|
darfDokumentBearbeiten(
|
||||||
|
[POSTEINGANG_TAG_ID],
|
||||||
|
[Permission.VIEW_FREIGABE],
|
||||||
|
MANUELL,
|
||||||
|
),
|
||||||
|
).toBe(false);
|
||||||
|
expect(
|
||||||
|
darfDokumentBearbeiten(undefined, [Permission.VIEW_INBOX], MANUELL),
|
||||||
|
).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { Permission } from '../auth/permissions.enum';
|
||||||
|
|
||||||
|
/** Paperless-Tag, der ein Dokument als „im Posteingang“ kennzeichnet. */
|
||||||
|
export const POSTEINGANG_TAG_ID = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Darf der Benutzer dieses Paperless-Dokument über die Posteingangs-Maske
|
||||||
|
* bearbeiten? Der Backend-Service-Token umgeht die Paperless-Rechte, deshalb
|
||||||
|
* wird hier pro Dokument geprüft: Posteingang-Rolle nur für Dokumente mit
|
||||||
|
* Posteingang-Tag, Buchhaltung nur für Dokumente mit Manuell-Tag.
|
||||||
|
*/
|
||||||
|
export function darfDokumentBearbeiten(
|
||||||
|
tags: number[] | undefined,
|
||||||
|
permissions: Permission[],
|
||||||
|
manuellTagId: number,
|
||||||
|
): boolean {
|
||||||
|
if (permissions.includes(Permission.MANAGE_ALL)) return true;
|
||||||
|
const vorhanden = new Set((tags ?? []).map(Number));
|
||||||
|
return (
|
||||||
|
(vorhanden.has(POSTEINGANG_TAG_ID) &&
|
||||||
|
permissions.includes(Permission.VIEW_INBOX)) ||
|
||||||
|
(vorhanden.has(manuellTagId) &&
|
||||||
|
permissions.includes(Permission.PROCESS_MANUALLY))
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -17,11 +17,13 @@ import {
|
|||||||
Res,
|
Res,
|
||||||
Query,
|
Query,
|
||||||
Request,
|
Request,
|
||||||
|
ForbiddenException,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import type { Response } from 'express';
|
import type { Response } from 'express';
|
||||||
import { AllowApiKey, RequirePermissions } from '../auth/permissions.decorator';
|
import { AllowApiKey, RequirePermissions } from '../auth/permissions.decorator';
|
||||||
import { Permission } from '../auth/permissions.enum';
|
import { Permission } from '../auth/permissions.enum';
|
||||||
import { entferneGeschuetzteStatusfelder } from './status-felder.util';
|
import { entferneGeschuetzteStatusfelder } from './status-felder.util';
|
||||||
|
import { darfDokumentBearbeiten } from './dokument-zugriff.util';
|
||||||
|
|
||||||
import { FileInterceptor } from '@nestjs/platform-express';
|
import { FileInterceptor } from '@nestjs/platform-express';
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
@@ -392,6 +394,23 @@ export class PaperlessController {
|
|||||||
// Fetch from paperless
|
// Fetch from paperless
|
||||||
const oldDocument = await this.paperlessService.getDocument(documentId);
|
const oldDocument = await this.paperlessService.getDocument(documentId);
|
||||||
|
|
||||||
|
// Nur Dokumente aus dem eigenen Arbeitsbereich (Posteingang bzw. Manuell)
|
||||||
|
// – sonst ließen sich Mandant/Felder beliebiger Dokumente ändern.
|
||||||
|
if (
|
||||||
|
!darfDokumentBearbeiten(
|
||||||
|
oldDocument.tags as number[] | undefined,
|
||||||
|
req.user?.permissions ?? [],
|
||||||
|
this.paperlessService.getManuellTagId(),
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
this.logger.warn(
|
||||||
|
`Dokument ${documentId}: Bearbeitung abgelehnt – nicht im Posteingang/Manuell-Bereich des Benutzers (${req.user?.preferredUsername ?? 'unbekannt'})`,
|
||||||
|
);
|
||||||
|
throw new ForbiddenException(
|
||||||
|
'Dieses Dokument liegt nicht in Ihrem Posteingang bzw. Ihrer Bearbeitungsliste',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
oldDocument.document_type = body.documentType ?? oldDocument.document_type;
|
oldDocument.document_type = body.documentType ?? oldDocument.document_type;
|
||||||
oldDocument.owner = body.mandant ?? oldDocument.owner;
|
oldDocument.owner = body.mandant ?? oldDocument.owner;
|
||||||
oldDocument.correspondent = body.correspondent ?? oldDocument.correspondent;
|
oldDocument.correspondent = body.correspondent ?? oldDocument.correspondent;
|
||||||
|
|||||||
@@ -215,11 +215,15 @@ export class PaperlessService {
|
|||||||
return response.data.results;
|
return response.data.results;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getManuellDocuments(): Promise<any[]> {
|
/** Tag der Liste „Manuell bearbeiten“ (Env-Werte kommen als String). */
|
||||||
const errorTag = this.configService.get<number>(
|
getManuellTagId(): number {
|
||||||
'MANUELL_BEARBEITEN_TAG',
|
return Number(
|
||||||
6,
|
this.configService.get<number | string>('MANUELL_BEARBEITEN_TAG', 6),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getManuellDocuments(): Promise<any[]> {
|
||||||
|
const errorTag = this.getManuellTagId();
|
||||||
const response = await this.client.get('/documents/', {
|
const response = await this.client.get('/documents/', {
|
||||||
params: {
|
params: {
|
||||||
page: 1,
|
page: 1,
|
||||||
|
|||||||
Reference in new issue
Block a user