Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
5 / 5
CRAP
100.00% covered (success)
100.00%
1 / 1
TemporarySignatureImageService
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
5 / 5
14
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 create
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
5
 isAvailable
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
4
 requireAvailable
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
3
 imageNotAvailable
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4/**
5 * SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
6 * SPDX-License-Identifier: AGPL-3.0-or-later
7 */
8
9namespace OCA\Libresign\Service;
10
11use OCA\Libresign\Exception\LibresignException;
12use OCP\IL10N;
13use OCP\ITempManager;
14
15/**
16 * Materializes a signature image for the current signing operation.
17 *
18 * Only stored image contents are suitable for rebuilding a missing temporary
19 * copy; the temporary path is not durable across Nextcloud requests or jobs.
20 */
21class TemporarySignatureImageService {
22    public function __construct(
23        private ITempManager $tempManager,
24        private IL10N $l10n,
25    ) {
26    }
27
28    public function create(int $nodeId, string $content): string {
29        $path = $this->tempManager->getTemporaryFile('_' . $nodeId . '.png');
30
31        if (!$path || $content === '' || @file_put_contents($path, $content) !== strlen($content) || !$this->isAvailable($path)) {
32            throw $this->imageNotAvailable();
33        }
34
35        return $path;
36    }
37
38    public function isAvailable(string $path): bool {
39        if ($path === '') {
40            return false;
41        }
42        clearstatcache(true, $path);
43        return is_file($path) && is_readable($path) && @filesize($path) > 0;
44    }
45
46    /** A missing image is valid for text-only and click-to-sign elements. */
47    public function requireAvailable(string $path): void {
48        if ($path !== '' && !$this->isAvailable($path)) {
49            throw $this->imageNotAvailable();
50        }
51    }
52
53    private function imageNotAvailable(): LibresignException {
54        // TRANSLATORS Error shown when LibreSign cannot prepare or read the visible signature image.
55        return new LibresignException($this->l10n->t('Temporary signature image is not available. Please try signing again.'));
56    }
57}