Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
90.91% covered (success)
90.91%
10 / 11
66.67% covered (warning)
66.67%
2 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
PdfValidator
90.91% covered (success)
90.91%
10 / 11
66.67% covered (warning)
66.67%
2 / 3
5.02
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 validate
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 validateDocMdpRestrictions
87.50% covered (warning)
87.50%
7 / 8
0.00% covered (danger)
0.00%
0 / 1
3.02
1<?php
2
3declare(strict_types=1);
4
5/**
6 * SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
7 * SPDX-License-Identifier: AGPL-3.0-or-later
8 */
9
10namespace OCA\Libresign\Service\File\Pdf;
11
12use OCA\Libresign\Exception\LibresignException;
13use OCA\Libresign\Handler\DocMdpHandler;
14use OCP\IL10N;
15
16class PdfValidator {
17    /**
18     * Semantic error code for a document whose DocMDP certification disallows additional signatures.
19     */
20    public const int CODE_DOCMDP_RESTRICTED = 4221;
21
22    public function __construct(
23        private PdfParser $pdfParser,
24        private DocMdpHandler $docMdpHandler,
25        private IL10N $l10n,
26    ) {
27    }
28
29    /**
30     * Validate PDF content and DocMDP restrictions.
31     *
32     * @param string $content The PDF content to validate
33     * @param string $fileName File name for error messages
34     * @throws LibresignException
35     */
36    public function validate(string $content, string $fileName): void {
37        $this->pdfParser->parse($content, $fileName);
38        $this->validateDocMdpRestrictions($content, $fileName);
39    }
40
41    private function validateDocMdpRestrictions(string $content, string $fileName): void {
42        $resource = fopen('php://memory', 'r+');
43        if (!is_resource($resource)) {
44            return;
45        }
46
47        try {
48            fwrite($resource, $content);
49            rewind($resource);
50
51            if (!$this->docMdpHandler->allowsAdditionalSignatures($resource)) {
52                // TRANSLATORS %s is the file name of the PDF with DocMDP restrictions
53                throw new LibresignException($this->l10n->t('This document has been certified with no changes allowed, so no additional signatures can be added: %s', [$fileName]), self::CODE_DOCMDP_RESTRICTED);
54            }
55        } finally {
56            fclose($resource);
57        }
58    }
59}