diff --git a/paperless-backend/src/paperless/dokument-zugriff.util.spec.ts b/paperless-backend/src/paperless/dokument-zugriff.util.spec.ts new file mode 100644 index 0000000..7edffc7 --- /dev/null +++ b/paperless-backend/src/paperless/dokument-zugriff.util.spec.ts @@ -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); + }); +}); diff --git a/paperless-backend/src/paperless/dokument-zugriff.util.ts b/paperless-backend/src/paperless/dokument-zugriff.util.ts new file mode 100644 index 0000000..5a43eac --- /dev/null +++ b/paperless-backend/src/paperless/dokument-zugriff.util.ts @@ -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)) + ); +} diff --git a/paperless-backend/src/paperless/paperless.controller.ts b/paperless-backend/src/paperless/paperless.controller.ts index b75cd16..c900118 100644 --- a/paperless-backend/src/paperless/paperless.controller.ts +++ b/paperless-backend/src/paperless/paperless.controller.ts @@ -17,11 +17,13 @@ import { Res, Query, Request, + ForbiddenException, } from '@nestjs/common'; import type { Response } from 'express'; import { AllowApiKey, RequirePermissions } from '../auth/permissions.decorator'; import { Permission } from '../auth/permissions.enum'; import { entferneGeschuetzteStatusfelder } from './status-felder.util'; +import { darfDokumentBearbeiten } from './dokument-zugriff.util'; import { FileInterceptor } from '@nestjs/platform-express'; import { InjectRepository } from '@nestjs/typeorm'; @@ -392,6 +394,23 @@ export class PaperlessController { // Fetch from paperless 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.owner = body.mandant ?? oldDocument.owner; oldDocument.correspondent = body.correspondent ?? oldDocument.correspondent; diff --git a/paperless-backend/src/paperless/paperless.service.ts b/paperless-backend/src/paperless/paperless.service.ts index 9a882bc..fcae76b 100644 --- a/paperless-backend/src/paperless/paperless.service.ts +++ b/paperless-backend/src/paperless/paperless.service.ts @@ -215,11 +215,15 @@ export class PaperlessService { return response.data.results; } - async getManuellDocuments(): Promise { - const errorTag = this.configService.get( - 'MANUELL_BEARBEITEN_TAG', - 6, + /** Tag der Liste „Manuell bearbeiten“ (Env-Werte kommen als String). */ + getManuellTagId(): number { + return Number( + this.configService.get('MANUELL_BEARBEITEN_TAG', 6), ); + } + + async getManuellDocuments(): Promise { + const errorTag = this.getManuellTagId(); const response = await this.client.get('/documents/', { params: { page: 1,