Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
88.24% covered (warning)
88.24%
45 / 51
80.00% covered (warning)
80.00%
4 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
ValidateService
88.24% covered (warning)
88.24%
45 / 51
80.00% covered (warning)
80.00%
4 / 5
30.37
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%
13 / 13
100.00% covered (success)
100.00%
1 / 1
6
 validateString
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
6
 validateArray
71.43% covered (warning)
71.43%
15 / 21
0.00% covered (danger)
0.00%
0 / 1
15.36
 validateNames
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
4
1<?php
2
3declare(strict_types=1);
4/**
5 * SPDX-FileCopyrightText: 2025 LibreCode coop and contributors
6 * SPDX-License-Identifier: AGPL-3.0-or-later
7 */
8
9namespace OCA\Libresign\Service\Certificate;
10
11use InvalidArgumentException;
12use OCP\IL10N;
13
14class ValidateService {
15
16    public function __construct(
17        protected RulesService $rulesService,
18        protected IL10N $l10n,
19    ) {
20
21    }
22
23    public function validate(string $fieldName, string|array $value): void {
24        $rule = $this->rulesService->getRule($fieldName);
25        $expectedType = $rule['type'] ?? 'string';
26
27        if ($expectedType === 'array' && !is_array($value)) {
28            throw new InvalidArgumentException(
29                // TRANSLATORS Error shown when generating a signing certificate and a required subject field has the wrong type. %s is the field name such as CN or O.
30                $this->l10n->t("Parameter '%s' is required!", [$fieldName])
31            );
32        }
33
34        if ($expectedType === 'string' && !is_string($value)) {
35            throw new InvalidArgumentException(
36                // TRANSLATORS Error shown when generating a signing certificate and a required subject field has the wrong type. %s is the field name such as CN or O.
37                $this->l10n->t("Parameter '%s' is required!", [$fieldName])
38            );
39        }
40
41        if ($expectedType === 'array') {
42            $this->validateArray($fieldName, $value, $rule);
43        } else {
44            $this->validateString($fieldName, $value, $rule);
45        }
46    }
47
48    private function validateString(string $fieldName, string $value, array $rule): void {
49        $value = trim($value);
50        $length = strlen($value);
51        if (!$length && isset($rule['required']) && $rule['required']) {
52            throw new InvalidArgumentException(
53                // TRANSLATORS Error shown when generating a signing certificate and a required subject field is empty. %s is the field name such as CN or O.
54                $this->l10n->t("Parameter '%s' is required!", [$fieldName])
55            );
56        }
57        if ($length > $rule['max'] || $length < $rule['min']) {
58            throw new InvalidArgumentException(
59                // TRANSLATORS Error shown when a certificate subject field length is outside the allowed range. %s is the field name; the next values are the minimum and maximum length.
60                $this->l10n->t("Parameter '%s' should be betweeen %s and %s.", [$fieldName, $rule['min'], $rule['max']])
61            );
62        }
63    }
64
65    private function validateArray(string $fieldName, array $values, array $rule): void {
66        $arrayLength = count($values);
67        if (isset($rule['minItems']) && $arrayLength < $rule['minItems']) {
68            throw new InvalidArgumentException(
69                // TRANSLATORS Error shown when a certificate subject field has too few values. %s is the field name with "items"; the next values are the allowed minimum and maximum counts.
70                $this->l10n->t("Parameter '%s' should be betweeen %s and %s.", [$fieldName . ' items', $rule['minItems'], $rule['maxItems'] ?? '∞'])
71            );
72        }
73        if (isset($rule['maxItems']) && $arrayLength > $rule['maxItems']) {
74            throw new InvalidArgumentException(
75                // TRANSLATORS Error shown when a certificate subject field has too many values. %s is the field name with "items"; the next values are the allowed minimum and maximum counts.
76                $this->l10n->t("Parameter '%s' should be betweeen %s and %s.", [$fieldName . ' items', $rule['minItems'] ?? 0, $rule['maxItems']])
77            );
78        }
79
80        $nonEmptyValues = array_filter($values, fn ($value) => is_string($value) && trim($value) !== '');
81
82        if (empty($nonEmptyValues) && isset($rule['required']) && $rule['required']) {
83            throw new InvalidArgumentException(
84                // TRANSLATORS Error shown when generating a signing certificate and a required subject field list is empty. %s is the field name.
85                $this->l10n->t("Parameter '%s' is required!", [$fieldName])
86            );
87        }
88
89        foreach ($values as $index => $value) {
90            if (!is_string($value)) {
91                throw new InvalidArgumentException(
92                    // TRANSLATORS Error shown when generating a signing certificate and a required subject field value is invalid. %s is the field name.
93                    $this->l10n->t("Parameter '%s' is required!", [$fieldName])
94                );
95            }
96
97            if (trim($value) !== '') {
98                $this->validateString($fieldName, $value, $rule);
99            }
100        }
101    }
102
103    public function validateNames(array $names): void {
104        foreach ($names as $item) {
105            if (empty($item['id'])) {
106                throw new InvalidArgumentException('Parameter id is required!');
107            }
108
109            if (!isset($item['value'])) {
110                throw new InvalidArgumentException("Parameter 'value' is required for field '{$item['id']}'!");
111            }
112
113            $this->validate($item['id'], $item['value']);
114        }
115    }
116
117}