Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
90.00% covered (success)
90.00%
54 / 60
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
SetupCheckUtils
90.00% covered (success)
90.00%
54 / 60
50.00% covered (danger)
50.00%
1 / 2
19.36
0.00% covered (danger)
0.00%
0 / 1
 verifyResourceIntegrity
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
1 / 1
11
 getErrorAndTipFromVerify
83.33% covered (warning)
83.33%
30 / 36
0.00% covered (danger)
0.00%
0 / 1
8.30
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\SetupCheck;
10
11use OCA\Libresign\Service\Install\SetupTrustMode;
12use OCA\Libresign\Service\Install\SignSetupService;
13use OCP\App\IAppManager;
14use OCP\IL10N;
15use OCP\IURLGenerator;
16use Psr\Log\LoggerInterface;
17
18trait SetupCheckUtils {
19    private SignSetupService $signSetupService;
20    private IURLGenerator $urlGenerator;
21    private IAppManager $appManager;
22    private LoggerInterface $logger;
23
24    private function verifyResourceIntegrity(string $resource, bool $debugEnabled): array {
25        // Debug mode does not imply that setup metadata was signed with the
26        // local development certificate. Official releases can also run with
27        // debug enabled, so always try the production trust chain first.
28        $result = $this->signSetupService->verify(
29            php_uname('m'),
30            $resource,
31            SetupTrustMode::Production,
32        );
33
34        if (!$debugEnabled || $result === []) {
35            return $result;
36        }
37
38        if (count($result) === 1
39            && (isset($result['SIGNATURE_DATA_NOT_FOUND']) || isset($result['EMPTY_SIGNATURE_DATA']))
40        ) {
41            return [];
42        }
43
44        if (!isset($result['HASH_FILE_ERROR'])) {
45            return $result;
46        }
47
48        // Development checkouts can have metadata signed with the local
49        // certificate. Only use that trust chain as a debug-mode fallback
50        // when verification with the production certificate could not
51        // validate the signed metadata.
52        $localResult = $this->signSetupService->verify(
53            php_uname('m'),
54            $resource,
55            SetupTrustMode::Development,
56        );
57
58        if ($localResult === []) {
59            return [];
60        }
61
62        if (isset($localResult['INVALID_HASH'])
63            || isset($localResult['FILE_MISSING'])
64            || isset($localResult['EXTRA_FILE'])
65        ) {
66            return $localResult;
67        }
68
69        return $result;
70    }
71
72    private function getErrorAndTipFromVerify(array $result, string $resource, bool $debugEnabled, IL10N $l10n): array {
73        if (count($result) === 1 && !$debugEnabled) {
74            if (isset($result['SIGNATURE_DATA_NOT_FOUND'])) {
75                return [
76                    // TRANSLATORS This refers to LibreSign binary integrity verification metadata, not to a user's document signature. LibreSign validates approved signing binaries using maintainer-signed metadata shipped with the app.
77                    $l10n->t('Binary integrity signature data not found.'),
78                    // TRANSLATORS This tip is shown when LibreSign seems to be running from source code instead of an official packaged release. %s is the occ command to enable debug mode.
79                    $l10n->t("It looks like this LibreSign instance is running from source code.\nEnable debug mode by running %s", ['occ config:system:set debug --value true --type boolean']),
80                ];
81            }
82            if (isset($result['EMPTY_SIGNATURE_DATA'])) {
83                return [
84                    // TRANSLATORS This refers to LibreSign binary integrity verification metadata, not to a user's document signature. LibreSign validates approved signing binaries using maintainer-signed metadata shipped with the app.
85                    $l10n->t('Binary integrity signature data is empty.'),
86                    // TRANSLATORS This tip is shown when LibreSign seems to be running from source code instead of an official packaged release. %s is the occ command to enable debug mode.
87                    $l10n->t("It looks like this LibreSign instance is running from source code.\nEnable debug mode by running %s", ['occ config:system:set debug --value true --type boolean']),
88                ];
89            }
90        }
91        if (isset($result['HASH_FILE_ERROR'])) {
92            $this->logger->error('Unable to verify binary integrity', ['result' => $result]);
93            if ($this->appManager->isEnabledForUser('logreader')) {
94                return [
95                    // TRANSLATORS LibreSign could not complete verification of the maintainer-signed binary integrity metadata. This does not necessarily mean that a downloaded binary has a wrong hash.
96                    $l10n->t('Unable to verify binary integrity.'),
97                    // TRANSLATORS %s is a link to the Nextcloud logging settings, where the technical cause of the integrity-verification failure can be inspected.
98                    $l10n->t('Check your nextcloud.log file on %s for the verification error before reinstalling the binaries.', [
99                        $this->urlGenerator->linkToRouteAbsolute('settings.adminsettings.form', ['section' => 'logging'])
100                    ]),
101                ];
102            }
103            return [
104                // TRANSLATORS LibreSign could not complete verification of the maintainer-signed binary integrity metadata. This does not necessarily mean that a downloaded binary has a wrong hash.
105                $l10n->t('Unable to verify binary integrity.'),
106                // TRANSLATORS The technical cause of an integrity-verification failure is written to the Nextcloud server log.
107                $l10n->t('Check your nextcloud.log file for the verification error before reinstalling the binaries.'),
108            ];
109        }
110        $this->logger->error('Invalid hash of binaries files', ['result' => $result]);
111        if ($this->appManager->isEnabledForUser('logreader')) {
112            return [
113                // TRANSLATORS This is a security/integrity check failure. LibreSign only accepts approved signing binaries whose hashes match maintainer-signed metadata shipped with the app. Even a one-bit change makes the binary invalid.
114                $l10n->t('Invalid hash of binaries files.'),
115                // TRANSLATORS %s is the occ command that downloads/reinstalls the approved LibreSign binaries.
116                $l10n->t('Check your nextcloud.log file on %s and run occ libresign:install --all', [
117                    $this->urlGenerator->linkToRouteAbsolute('settings.adminsettings.form', ['section' => 'logging'])
118                ]),
119            ];
120        }
121        return [
122            // TRANSLATORS This is a security/integrity check failure. LibreSign only accepts approved signing binaries whose hashes match maintainer-signed metadata shipped with the app. Even a one-bit change makes the binary invalid.
123            $l10n->t('Invalid hash of binaries files.'),
124            // TRANSLATORS %s is the occ command that downloads/reinstalls the approved LibreSign binaries.
125            $l10n->t('Check your nextcloud.log file and run occ libresign:install --all'),
126        ];
127    }
128}