Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
31 / 31
100.00% covered (success)
100.00%
7 / 7
CRAP
100.00% covered (success)
100.00%
1 / 1
LibreSignConfigurationCollector
100.00% covered (success)
100.00%
31 / 31
100.00% covered (success)
100.00%
7 / 7
15
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
 metricIds
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 collect
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
2
 signatureEngine
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 signingMode
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 certificateEngine
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 isRootCaConfigured
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
5
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\UsageStatistics\Collector;
10
11use OCA\Libresign\AppInfo\Application;
12use OCA\Libresign\Service\UsageStatistics\Contract\IMetricCollector;
13use OCA\Libresign\Service\UsageStatistics\Model\MetricValue;
14use OCA\Libresign\Service\UsageStatistics\Model\ReportMode;
15use OCA\Libresign\Service\UsageStatistics\Model\ReportPeriod;
16use OCP\App\IAppManager;
17use OCP\IAppConfig;
18
19/**
20 * Current LibreSign configuration. Values are read from the stored settings
21 * only: building the certificate engine could create the PKI directory or
22 * contact the CFSSL server, and a report must not change anything.
23 */
24class LibreSignConfigurationCollector implements IMetricCollector {
25    private const CERTIFICATE_ENGINES = ['openssl', 'cfssl', 'none'];
26
27    public function __construct(
28        private IAppManager $appManager,
29        private IAppConfig $appConfig,
30    ) {
31    }
32
33    #[\Override]
34    public function metricIds(): array {
35        return [
36            'libresign.version',
37            'libresign.signature_engine',
38            'libresign.signing_mode',
39            'certificate.engine',
40            'certificate.root_ca_configured',
41        ];
42    }
43
44    #[\Override]
45    public function collect(ReportPeriod $period, ReportMode $mode): array {
46        if ($mode === ReportMode::HISTORICAL) {
47            return array_fill_keys($this->metricIds(), MetricValue::unavailable());
48        }
49
50        $certificateEngine = $this->certificateEngine();
51        return [
52            'libresign.version' => MetricValue::of($this->appManager->getAppVersion(Application::APP_ID)),
53            'libresign.signature_engine' => MetricValue::of($this->signatureEngine()),
54            'libresign.signing_mode' => MetricValue::of($this->signingMode()),
55            'certificate.engine' => MetricValue::of($certificateEngine),
56            'certificate.root_ca_configured' => MetricValue::of($this->isRootCaConfigured($certificateEngine)),
57        ];
58    }
59
60    /** Same fallback as the admin settings: anything but PhpNative runs JSignPdf. */
61    private function signatureEngine(): string {
62        $engine = $this->appConfig->getValueString(Application::APP_ID, 'signature_engine', 'JSignPdf');
63        return $engine === 'PhpNative' ? $engine : 'JSignPdf';
64    }
65
66    /** Same fallback as the signing mode policy. */
67    private function signingMode(): string {
68        $mode = $this->appConfig->getValueString(Application::APP_ID, 'signing_mode', 'sync');
69        return in_array($mode, ['sync', 'async'], true) ? $mode : 'sync';
70    }
71
72    private function certificateEngine(): string {
73        $engine = $this->appConfig->getValueString(Application::APP_ID, 'certificate_engine', 'openssl');
74        return in_array($engine, self::CERTIFICATE_ENGINES, true) ? $engine : 'other';
75    }
76
77    private function isRootCaConfigured(string $certificateEngine): bool {
78        if (!in_array($certificateEngine, ['openssl', 'cfssl'], true)) {
79            return false;
80        }
81        $configPath = $this->appConfig->getValueString(Application::APP_ID, 'config_path');
82        if ($configPath === '' || !is_dir($configPath)) {
83            return false;
84        }
85        return file_exists($configPath . DIRECTORY_SEPARATOR . 'ca.pem')
86            && file_exists($configPath . DIRECTORY_SEPARATOR . 'ca-key.pem');
87    }
88}