• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

LibreSign / libresign / 4662495988

pending completion
4662495988

Pull #1611

github

GitHub
Merge 204029401 into c37ea17cc
Pull Request #1611: [stable25] Drop libresign cli

14 of 15 new or added lines in 2 files covered. (93.33%)

40 existing lines in 1 file now uncovered.

2529 of 4428 relevant lines covered (57.11%)

4.59 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

22.63
/lib/Service/InstallService.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace OCA\Libresign\Service;
6

7
use OC\Archive\TAR;
8
use OC\Archive\ZIP;
9
use OC\Files\Filesystem;
10
use OC\Memcache\NullCache;
11
use OCA\Libresign\AppInfo\Application;
12
use OCA\Libresign\Exception\LibresignException;
13
use OCA\Libresign\Handler\CfsslHandler;
14
use OCA\Libresign\Handler\CfsslServerHandler;
15
use OCA\Libresign\Handler\JSignPdfHandler;
16
use OCP\Files\File;
17
use OCP\Files\Folder;
18
use OCP\Files\IRootFolder;
19
use OCP\Files\NotFoundException;
20
use OCP\Http\Client\IClientService;
21
use OCP\ICache;
22
use OCP\ICacheFactory;
23
use OCP\IConfig;
24
use Psr\Log\LoggerInterface;
25
use RuntimeException;
26
use Symfony\Component\Console\Helper\ProgressBar;
27
use Symfony\Component\Console\Output\OutputInterface;
28
use Symfony\Component\Process\Process;
29

30
class InstallService {
31
        public const JAVA_VERSION = 'openjdk version "17.0.5" 2022-10-18';
32
        private const JAVA_PARTIAL_VERSION = '17.0.5_8';
33
        /**
34
         * When update, verify the hash of all architectures
35
         */
36
        public const CFSSL_VERSION = '1.6.3';
37
        /** @var ICache */
38
        private $cache;
39
        /** @var IConfig */
40
        public $config;
41
        /** @var IClientService */
42
        private $clientService;
43
        /** @var IRootFolder */
44
        private $rootFolder;
45
        /** @var CfsslServerHandler */
46
        private $cfsslServerHandler;
47
        /** @var CfsslHandler */
48
        private $cfsslHandler;
49
        /** @var OutputInterface */
50
        private $output;
51
        /** @var bool */
52
        /** @var string */
53
        private $resource = '';
54
        /** @var LoggerInterface */
55
        private $logger;
56

57
        public function __construct(
58
                ICacheFactory $cacheFactory,
59
                IClientService $clientService,
60
                CfsslServerHandler $cfsslServerHandler,
61
                CfsslHandler $cfsslHandler,
62
                IConfig $config,
63
                IRootFolder $rootFolder,
64
                LoggerInterface $logger
65
        ) {
66
                $this->cache = $cacheFactory->createDistributed('libresign-setup');
47✔
67
                $this->clientService = $clientService;
47✔
68
                $this->cfsslServerHandler = $cfsslServerHandler;
47✔
69
                $this->cfsslHandler = $cfsslHandler;
47✔
70
                $this->config = $config;
47✔
71
                $this->rootFolder = $rootFolder;
47✔
72
                $this->logger = $logger;
47✔
73
        }
74

75
        public function setOutput(OutputInterface $output): void {
76
                $this->output = $output;
4✔
77
        }
78

79
        private function getFolder(string $path = ''): Folder {
80
                $rootFolder = $this->getAppRootFolder();
216✔
81
                if ($rootFolder->nodeExists(Application::APP_ID . DIRECTORY_SEPARATOR . $path)) {
216✔
82
                        $folder = $rootFolder->get(Application::APP_ID . DIRECTORY_SEPARATOR . $path);
210✔
83
                } else {
84
                        $folder = $rootFolder->newFolder(Application::APP_ID . DIRECTORY_SEPARATOR . $path);
60✔
85
                }
86
                return $folder;
216✔
87
        }
88

89
        private function getAppDataFolderName(): string {
90
                $instanceId = $this->config->getSystemValue('instanceid', null);
216✔
91
                if ($instanceId === null) {
216✔
92
                        throw new \RuntimeException('no instance id!');
×
93
                }
94

95
                return 'appdata_' . $instanceId;
216✔
96
        }
97

98
        private function getDataDir(): string {
99
                $dataDir = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data/');
216✔
100
                return $dataDir;
216✔
101
        }
102

103
        private function getAppRootFolder(): Folder {
104
                $path = $this->getAppDataFolderName();
216✔
105
                $mount = Filesystem::getMountManager()->find($path);
216✔
106
                $storage = $mount->getStorage();
216✔
107
                $internalPath = $mount->getInternalPath($path);
216✔
108
                if ($storage->file_exists($internalPath)) {
216✔
109
                        $folder = $this->rootFolder->get($path);
211✔
110
                } else {
111
                        $folder = $this->rootFolder->newFolder($path);
59✔
112
                }
113
                return $folder;
216✔
114
        }
115

116
        public function getFullPath(): string {
117
                $folder = $this->getFolder();
216✔
118
                return $this->getDataDir() . '/' . $folder->getInternalPath();
216✔
119
        }
120

121
        /**
122
         * Return the config path, create if not exist.
123
         *
124
         * @return string Full config path
125
         */
126
        public function getConfigPath(): string {
127
                $this->getFolder('cfssl_config');
1✔
128
                return $this->getFullPath() . DIRECTORY_SEPARATOR . 'cfssl_config' . DIRECTORY_SEPARATOR;
1✔
129
        }
130

131
        private function runAsync(): void {
132
                $resource = $this->resource;
×
133
                $process = new Process(['./occ', 'libresign:install', '--' . $resource]);
×
134
                $process->start();
×
135
                $data['pid'] = $process->getPid();
×
136
                if ($data['pid']) {
×
137
                        $this->setCache($resource, $data);
×
138
                }
139
        }
140

141
        private function progressToDatabase(int $downloadSize, int $downloaded): void {
UNCOV
142
                $data = $this->getProressData();
×
UNCOV
143
                $data['download_size'] = $downloadSize;
×
UNCOV
144
                $data['downloaded'] = $downloaded;
×
UNCOV
145
                $this->setCache($this->resource, $data);
×
146
        }
147

148
        public function getProressData(): array {
UNCOV
149
                $data = $this->getCache($this->resource) ?? [];
×
UNCOV
150
                return $data;
×
151
        }
152

153
        private function removeDownloadProgress(): void {
UNCOV
154
                $this->removeCache($this->resource);
×
155
        }
156

157
        /**
158
         * @param string $key
159
         * @param mixed $value
160
         * @return void
161
         */
162
        private function setCache(string $key, $value): void {
UNCOV
163
                if ($this->cache instanceof NullCache) {
×
164
                        $appFolder = $this->getFolder();
×
165
                        try {
166
                                /** @var File */
167
                                $file = $appFolder->get('setup-cache.json');
×
168
                        } catch (\Throwable $th) {
×
169
                                /** @var File */
170
                                $file = $appFolder->newFile('setup-cache.json', '[]');
×
171
                        }
172
                        $json = $file->getContent() ? json_decode($file->getContent(), true) : [];
×
173
                        $json[$key] = $value;
×
174
                        $file->putContent(json_encode($json));
×
175
                        return;
×
176
                }
UNCOV
177
                $this->cache->set(Application::APP_ID . '-asyncDownloadProgress-' . $key, $value);
×
178
        }
179

180
        /**
181
         * @param string $key
182
         * @return mixed
183
         */
184
        private function getCache(string $key) {
UNCOV
185
                if ($this->cache instanceof NullCache) {
×
186
                        $appFolder = $this->getFolder();
×
187
                        try {
188
                                /** @var File */
189
                                $file = $appFolder->get('setup-cache.json');
×
190
                                $json = $file->getContent() ? json_decode($file->getContent(), true) : [];
×
191
                                return $json[$key] ?? null;
×
192
                        } catch (\Throwable $th) {
×
193
                        }
194
                        return;
×
195
                }
UNCOV
196
                return $this->cache->get(Application::APP_ID . '-asyncDownloadProgress-' . $key);
×
197
        }
198

199
        private function removeCache(string $key): void {
UNCOV
200
                if ($this->cache instanceof NullCache) {
×
201
                        $appFolder = $this->getFolder();
×
202
                        try {
203
                                $file = $appFolder->get('setup-cache.json');
×
204
                                $file->delete();
×
205
                        } catch (\Throwable $th) {
×
206
                        }
207
                        return;
×
208
                }
UNCOV
209
                $this->cache->remove(Application::APP_ID . '-asyncDownloadProgress-' . $key);
×
210
        }
211

212
        public function getTotalSize(): array {
213
                $resources = [
×
214
                        'java',
×
215
                        'jsignpdf',
×
216
                        'cfssl'
×
217
                ];
×
218
                $return = [];
×
219
                foreach ($resources as $resource) {
×
220
                        $this->setResource($resource);
×
221
                        $progressData = $this->getProressData();
×
222
                        if (array_key_exists('download_size', $progressData)) {
×
223
                                if ($progressData['download_size']) {
×
224
                                        $return[$resource] = $progressData['downloaded'] * 100 / $progressData['download_size'];
×
225
                                } else {
226
                                        $return[$resource] = 0;
×
227
                                }
228
                        }
229
                }
230
                return $return;
×
231
        }
232

233
        public function setResource(string $resource): self {
UNCOV
234
                $this->resource = $resource;
×
UNCOV
235
                return $this;
×
236
        }
237

238
        public function installJava(?bool $async = false): void {
239
                $this->setResource('java');
×
240
                if ($async) {
×
241
                        $this->runAsync();
×
242
                        return;
×
243
                }
244
                $extractDir = $this->getFullPath() . DIRECTORY_SEPARATOR . 'java';
×
245
                $appFolder = $this->getFolder();
×
246
                if ($appFolder->nodeExists('java')) {
×
247
                        /** @var Folder */
248
                        $javaFolder = $appFolder->get('java');
×
249
                } else {
250
                        $javaFolder = $appFolder->newFolder('java');
×
251
                }
252

253
                /**
254
                 * Steps to update:
255
                 *     Check the compatible version of Java to use JSignPdf
256
                 *     Update all the follow data
257
                 *     Update the constants with java version
258
                 * URL used to get the MD5 and URL to download:
259
                 * https://jdk.java.net/java-se-ri/8-MR3
260
                 */
261
                if (PHP_OS_FAMILY === 'Linux') {
×
262
                        $architecture = php_uname('m');
×
263
                        if ($architecture === 'x86_64') {
×
264
                                $compressedFileName = 'OpenJDK17U-jre_x64_linux_hotspot_' . self::JAVA_PARTIAL_VERSION . '.tar.gz';
×
265
                                $url = 'https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.5%2B8/' . $compressedFileName;
×
266
                        } elseif ($architecture === 'aarch64') {
×
267
                                $compressedFileName = 'OpenJDK17U-jre_aarch64_linux_hotspot_' . self::JAVA_PARTIAL_VERSION . '.tar.gz';
×
268
                                $url = 'https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.5%2B8/' . $compressedFileName;
×
269
                        }
270
                        $class = TAR::class;
×
271
                } else {
272
                        throw new RuntimeException(sprintf('OS_FAMILY %s is incompatible with LibreSign.', PHP_OS_FAMILY));
×
273
                }
274
                $folder = $this->getFolder();
×
275
                $checksumUrl = $url . '.sha256.txt';
×
276
                $hash = $this->getHash($folder, 'java', $compressedFileName, self::JAVA_PARTIAL_VERSION, $checksumUrl);
×
277
                if (!$javaFolder->nodeExists($compressedFileName)) {
×
278
                        $compressedFile = $javaFolder->newFile($compressedFileName);
×
279
                } else {
280
                        $compressedFile = $javaFolder->get($compressedFileName);
×
281
                }
282
                $comporessedInternalFileName = $this->getDataDir() . DIRECTORY_SEPARATOR . $compressedFile->getInternalPath();
×
283

284
                $this->download($url, 'java', $comporessedInternalFileName, $hash, 'sha256');
×
285

286
                $this->config->deleteAppValue(Application::APP_ID, 'java_path');
×
287
                $extractor = new $class($comporessedInternalFileName);
×
288
                $extractor->extract($extractDir);
×
289

290
                $this->config->setAppValue(Application::APP_ID, 'java_path', $extractDir . '/jdk-17.0.5+8-jre/bin/java');
×
291
                $this->removeDownloadProgress();
×
292
        }
293

294
        public function uninstallJava(): void {
295
                $javaPath = $this->config->getAppValue(Application::APP_ID, 'java_path');
×
296
                if (!$javaPath) {
×
297
                        return;
×
298
                }
299
                $appFolder = $this->getAppRootFolder();
×
300
                $name = $appFolder->getName();
×
301
                if (!strpos($javaPath, $name)) {
×
302
                        return;
×
303
                }
304
                if (PHP_OS_FAMILY !== 'Windows') {
×
305
                        exec('rm -rf ' . $this->getDataDir() . '/' . $this->getFolder()->getInternalPath() . '/java');
×
306
                }
307
                if ($appFolder->nodeExists('/libresign/java')) {
×
308
                        $javaFolder = $appFolder->get('/libresign/java');
×
309
                        $javaFolder->delete();
×
310
                }
311
                $this->config->deleteAppValue(Application::APP_ID, 'java_path');
×
312
        }
313

314
        public function installJSignPdf(?bool $async = false): void {
315
                if (!extension_loaded('zip')) {
×
316
                        throw new RuntimeException('Zip extension is not available');
×
317
                }
318
                $this->setResource('jsignpdf');
×
319
                if ($async) {
×
320
                        $this->runAsync();
×
321
                        return;
×
322
                }
323
                $extractDir = $this->getFullPath();
×
324

325
                $compressedFileName = 'jsignpdf-' . JSignPdfHandler::VERSION . '.zip';
×
326
                if (!$this->getFolder()->nodeExists($compressedFileName)) {
×
327
                        $compressedFile = $this->getFolder()->newFile($compressedFileName);
×
328
                } else {
329
                        $compressedFile = $this->getFolder()->get($compressedFileName);
×
330
                }
331
                $comporessedInternalFileName = $this->getDataDir() . DIRECTORY_SEPARATOR . $compressedFile->getInternalPath();
×
332
                $url = 'https://sourceforge.net/projects/jsignpdf/files/stable/JSignPdf%20' . JSignPdfHandler::VERSION . '/jsignpdf-' . JSignPdfHandler::VERSION . '.zip';
×
333
                /** WHEN UPDATE version: generate this hash handmade and update here */
334
                $hash = '327182016506f57109270d4875851784';
×
335

336
                $this->download($url, 'JSignPdf', $comporessedInternalFileName, $hash);
×
337

338
                $zip = new ZIP($extractDir . DIRECTORY_SEPARATOR . $compressedFileName);
×
339
                $zip->extract($extractDir);
×
340

341
                $fullPath = $extractDir . DIRECTORY_SEPARATOR . 'jsignpdf-' . JSignPdfHandler::VERSION . DIRECTORY_SEPARATOR . 'JSignPdf.jar';
×
342
                $this->config->setAppValue(Application::APP_ID, 'jsignpdf_jar_path', $fullPath);
×
343
                $this->removeDownloadProgress();
×
344
        }
345

346
        public function uninstallJSignPdf(): void {
347
                $jsignpdJarPath = $this->config->getAppValue(Application::APP_ID, 'jsignpdf_jar_path');
×
348
                if (!$jsignpdJarPath) {
×
349
                        return;
×
350
                }
351
                $appFolder = $this->getAppRootFolder();
×
352
                $name = $appFolder->getName();
×
353
                // Remove prefix
354
                $path = explode($name, $jsignpdJarPath)[1];
×
355
                // Remove sufix
356
                $path = trim($path, DIRECTORY_SEPARATOR . 'JSignPdf.jar');
×
357
                try {
358
                        $folder = $appFolder->get($path);
×
359
                        $folder->delete();
×
360
                } catch (NotFoundException $e) {
×
361
                }
362
                $this->config->deleteAppValue(Application::APP_ID, 'jsignpdf_jar_path');
×
363
        }
364

365
        public function installCfssl(?bool $async = false): void {
UNCOV
366
                $this->setResource('cfssl');
×
367
                if ($async) {
×
368
                        $this->runAsync();
×
369
                        return;
×
370
                }
371
                if (PHP_OS_FAMILY !== 'Linux') {
×
372
                        throw new RuntimeException(sprintf('OS_FAMILY %s is incompatible with LibreSign.', PHP_OS_FAMILY));
×
373
                }
374
                $architecture = php_uname('m');
×
375
                if ($architecture === 'x86_64') {
×
376
                        $this->installCfssl64();
×
377
                } elseif ($architecture === 'aarch64') {
×
378
                        $this->installCfsslArm();
×
379
                }
380
                $this->removeDownloadProgress();
×
381
        }
382

383
        private function installCfssl64(): void {
384
                $folder = $this->getFolder();
×
385

386
                $downloads = [
×
387
                        [
×
388
                                'file' => 'cfssl_' . self::CFSSL_VERSION . '_linux_amd64',
×
389
                                'destination' => 'cfssl',
×
390
                        ],
×
391
                        [
×
392
                                'file' => 'cfssljson_' . self::CFSSL_VERSION . '_linux_amd64',
×
393
                                'destination' => 'cfssljson',
×
394
                        ],
×
395
                ];
×
396
                $baseUrl = 'https://github.com/cloudflare/cfssl/releases/download/v' . self::CFSSL_VERSION . '/';
×
397
                $checksumUrl = 'https://github.com/cloudflare/cfssl/releases/download/v' . self::CFSSL_VERSION . '/cfssl_' . self::CFSSL_VERSION . '_checksums.txt';
×
398
                foreach ($downloads as $download) {
×
NEW
399
                        $hash = $this->getHash($folder, 'cfssl', $download['file'], self::CFSSL_VERSION, $checksumUrl);
×
400

401
                        $file = $folder->newFile($download['destination']);
×
402
                        $fullPath = $this->getDataDir() . DIRECTORY_SEPARATOR . $file->getInternalPath();
×
403

404
                        $this->download($baseUrl . $download['file'], $download['destination'], $fullPath, $hash, 'sha256');
×
405

406
                        chmod($fullPath, 0700);
×
407
                }
408

409
                $cfsslBinPath = $this->getDataDir() . DIRECTORY_SEPARATOR .
×
410
                        $this->getFolder()->getInternalPath() . DIRECTORY_SEPARATOR .
×
411
                        $downloads[0]['destination'];
×
412
                $this->config->setAppValue(Application::APP_ID, 'cfssl_bin', $cfsslBinPath);
×
413
        }
414

415
        private function installCfsslArm(): void {
416
                $appFolder = $this->getFolder();
×
417
                if ($appFolder->nodeExists('cfssl')) {
×
418
                        /** @var Folder */
419
                        $cfsslFolder = $appFolder->get('cfssl');
×
420
                } else {
421
                        $cfsslFolder = $appFolder->newFolder('cfssl');
×
422
                }
423
                $compressedFileName = 'cfssl-' . self::CFSSL_VERSION . '-1-aarch64.pkg.tar.xz';
×
424
                $url = 'http://mirror.archlinuxarm.org/aarch64/community/' . $compressedFileName;
×
425
                // Generated handmade with command sha256sum
426
                $hash = '944a6c54e53b0e2ef04c9b22477eb5f637715271c74ccea9bb91d7ac0473b855';
×
427
                if (!$cfsslFolder->nodeExists($compressedFileName)) {
×
428
                        $compressedFile = $cfsslFolder->newFile($compressedFileName);
×
429
                } else {
430
                        $compressedFile = $cfsslFolder->get($compressedFileName);
×
431
                }
432

433
                $comporessedInternalFileName = $this->getDataDir() . DIRECTORY_SEPARATOR . $compressedFile->getInternalPath();
×
434

435
                $this->download($url, 'cfssl', $comporessedInternalFileName, $hash, 'sha256');
×
436

437
                $this->config->deleteAppValue(Application::APP_ID, 'cfssl_bin');
×
438
                $extractor = new TAR($comporessedInternalFileName);
×
439

440
                $extractDir = $this->getFullPath() . DIRECTORY_SEPARATOR . 'cfssl';
×
441
                $result = $extractor->extract($extractDir);
×
442
                if (!$result) {
×
443
                        throw new \RuntimeException('Error to extract xz file. Install xz. Read more: https://github.com/codemasher/php-ext-xz');
×
444
                }
445
                $cfsslBinPath = $this->getDataDir() . DIRECTORY_SEPARATOR .
×
446
                        $this->getFolder()->getInternalPath() . DIRECTORY_SEPARATOR .
×
447
                        'cfssl/usr/bin/cfssl';
×
448
                $this->config->setAppValue(Application::APP_ID, 'cfssl_bin', $cfsslBinPath);
×
449
        }
450

451
        public function uninstallCfssl(): void {
452
                $cfsslPath = $this->config->getAppValue(Application::APP_ID, 'cfssl_bin');
×
453
                if (!$cfsslPath) {
×
454
                        return;
×
455
                }
456
                $appFolder = $this->getAppRootFolder();
×
457
                $name = $appFolder->getName();
×
458
                // Remove prefix
459
                $path = explode($name, $cfsslPath)[1];
×
460
                try {
461
                        $folder = $appFolder->get($path);
×
462
                        $folder->delete();
×
463
                } catch (NotFoundException $e) {
×
464
                }
465
                $this->config->deleteAppValue(Application::APP_ID, 'cfssl_bin');
×
466
        }
467

468
        public function isCfsslBinInstalled(): bool {
469
                if ($this->config->getAppValue(Application::APP_ID, 'cfssl_bin')) {
×
470
                        return true;
×
471
                }
472
                return false;
×
473
        }
474

475
        protected function download(string $url, string $filename, string $path, ?string $hash = '', ?string $hash_algo = 'md5'): void {
UNCOV
476
                if (file_exists($path)) {
×
UNCOV
477
                        $this->progressToDatabase((int) filesize($path), 0);
×
UNCOV
478
                        if (hash_file($hash_algo, $path) === $hash) {
×
UNCOV
479
                                return;
×
480
                        }
481
                }
UNCOV
482
                if (php_sapi_name() === 'cli' && $this->output instanceof OutputInterface) {
×
483
                        $this->downloadCli($url, $filename, $path, $hash, $hash_algo);
×
484
                        return;
×
485
                }
UNCOV
486
                $client = $this->clientService->newClient();
×
487
                try {
UNCOV
488
                        $client->get($url, [
×
UNCOV
489
                                'sink' => $path,
×
UNCOV
490
                                'timeout' => 0,
×
UNCOV
491
                                'progress' => function ($downloadSize, $downloaded) {
×
UNCOV
492
                                        $this->progressToDatabase($downloadSize, $downloaded);
×
UNCOV
493
                                },
×
UNCOV
494
                        ]);
×
495
                } catch (\Exception $e) {
×
496
                        throw new LibresignException('Failure on download ' . $filename . " try again.\n" . $e->getMessage());
×
497
                }
UNCOV
498
                if ($hash && file_exists($path) && hash_file($hash_algo, $path) !== $hash) {
×
499
                        throw new LibresignException('Failure on download ' . $filename . ' try again. Invalid ' . $hash_algo . '.');
×
500
                }
501
        }
502

503
        protected function downloadCli(string $url, string $filename, string $path, ?string $hash = '', ?string $hash_algo = 'md5'): void {
504
                $client = $this->clientService->newClient();
4✔
505
                $progressBar = new ProgressBar($this->output);
4✔
506
                $this->output->writeln('Downloading ' . $filename . '...');
4✔
507
                $progressBar->start();
4✔
508
                try {
509
                        $client->get($url, [
4✔
510
                                'sink' => $path,
4✔
511
                                'timeout' => 0,
4✔
512
                                'progress' => function ($downloadSize, $downloaded) use ($progressBar) {
4✔
513
                                        $progressBar->setMaxSteps($downloadSize);
×
514
                                        $progressBar->setProgress($downloaded);
×
515
                                        $this->progressToDatabase($downloadSize, $downloaded);
×
516
                                },
4✔
517
                        ]);
4✔
518
                } catch (\Exception $e) {
×
519
                        $this->output->writeln('<error>Failure on download ' . $filename . ' try again.</error>');
×
520
                        $this->output->writeln('<error>' . $e->getMessage() . '</error>');
×
521
                        $this->logger->error('Failure on download ' . $filename . '. ' . $e->getMessage());
×
522
                }
523
                $progressBar->finish();
4✔
524
                $this->output->writeln('');
4✔
525
                $progressBar->finish();
4✔
526
                if ($hash && file_exists($path) && hash_file($hash_algo, $path) !== $hash) {
4✔
527
                        $this->output->writeln('<error>Failure on download ' . $filename . ' try again</error>');
2✔
528
                        $this->output->writeln('<error>Invalid ' . $hash_algo . '</error>');
2✔
529
                        $this->logger->error('Failure on download ' . $filename . '. Invalid ' . $hash_algo . '.');
2✔
530
                }
531
                if (!file_exists($path)) {
4✔
532
                        $this->output->writeln('<error>Failure on download ' . $filename . ', empty file, try again</error>');
1✔
533
                        $this->logger->error('Failure on download ' . $filename . ', empty file.');
1✔
534
                }
535
        }
536

537
        private function getHash(Folder $folder, string $type, string $file, string $version, string $checksumUrl): string {
UNCOV
538
                $hashFileName = 'checksums_' . $type . '_' . $version . '.txt';
×
UNCOV
539
                if (!$folder->nodeExists($hashFileName)) {
×
UNCOV
540
                        $hashes = file_get_contents($checksumUrl);
×
UNCOV
541
                        if (!$hashes) {
×
542
                                throw new LibresignException('Failute to download hash file. URL: ' . $checksumUrl);
×
543
                        }
UNCOV
544
                        $folder->newFile($hashFileName, $hashes);
×
545
                }
546
                /** @var \OCP\Files\File */
UNCOV
547
                $fileObject = $folder->get($hashFileName);
×
UNCOV
548
                $hashes = $fileObject->getContent();
×
UNCOV
549
                if (!$hashes) {
×
550
                        throw new LibresignException(
×
551
                                'Failute to load content of hash file: ' . $hashFileName . '. ' .
×
552
                                'File corrupted or not found. Run "occ files:scan-app-data libresign".'
×
553
                        );
×
554
                }
UNCOV
555
                preg_match('/(?<hash>\w*) +' . $file . '/', $hashes, $matches);
×
UNCOV
556
                return $matches['hash'];
×
557
        }
558

559
        public function generate(
560
                string $commonName,
561
                array $names = [],
562
                string $configPath = '',
563
                string $cfsslUri = '',
564
                string $binary = ''
565
        ): void {
566
                $key = bin2hex(random_bytes(16));
2✔
567

568
                if (!$configPath) {
2✔
569
                        $configPath = $this->getConfigPath();
1✔
570
                }
571
                $this->cfsslHandler->setConfigPath($configPath);
2✔
572
                $this->cfsslServerHandler->createConfigServer(
2✔
573
                        $commonName,
2✔
574
                        $names,
2✔
575
                        $key,
2✔
576
                        $configPath
2✔
577
                );
2✔
578
                if (!$cfsslUri) {
2✔
579
                        $cfsslUri = CfsslHandler::CFSSL_URI;
×
580
                        if (!$binary) {
×
581
                                $binary = $this->config->getAppValue(Application::APP_ID, 'cfssl_bin');
×
582
                                if ($binary && !file_exists($binary)) {
×
583
                                        $this->config->deleteAppValue(Application::APP_ID, 'cfssl_bin');
×
584
                                        $binary = '';
×
585
                                }
586
                                if (!$binary) {
×
587
                                        /**
588
                                         * @todo Suggestion: run this in a background proccess
589
                                         * to make more fast the setup and, maybe, implement a new endpoint
590
                                         * to start downloading of all binaries files in a background process
591
                                         * and return the status progress of download.
592
                                         */
593
                                        $this->installCfssl();
×
594
                                        $binary = $this->config->getAppValue(Application::APP_ID, 'cfssl_bin');
×
595
                                }
596
                        }
597
                }
598
                $this->cfsslHandler->setCfsslUri($cfsslUri);
2✔
599
                if ($binary) {
2✔
600
                        $this->cfsslHandler->setBinary($binary);
×
601
                        $this->cfsslHandler->genkey();
×
602
                }
603
                for ($i = 1; $i <= 4; $i++) {
2✔
604
                        if ($this->cfsslHandler->health($cfsslUri)) {
2✔
605
                                break;
1✔
606
                        }
607
                        // @codeCoverageIgnoreStart
608
                        sleep(2);
609
                        // @codeCoverageIgnoreEnd
610
                }
611

612
                $this->config->setAppValue(Application::APP_ID, 'rootCert', json_encode([
1✔
613
                        'commonName' => $commonName,
1✔
614
                        'names' => $names
1✔
615
                ]));
1✔
616
                $this->config->setAppValue(Application::APP_ID, 'authkey', $key);
1✔
617
                $this->config->setAppValue(Application::APP_ID, 'cfsslUri', $cfsslUri);
1✔
618
                $this->config->setAppValue(Application::APP_ID, 'configPath', $configPath);
1✔
619
                $this->config->setAppValue(Application::APP_ID, 'notifyUnsignedUser', 1);
1✔
620
        }
621
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc