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

LibreSign / libresign / 19137174086

06 Nov 2025 01:25PM UTC coverage: 39.311%. First build
19137174086

Pull #5757

github

web-flow
Merge b64de61b5 into f56fcda6c
Pull Request #5757: feat: use crl by cert

54 of 116 new or added lines in 11 files covered. (46.55%)

4599 of 11699 relevant lines covered (39.31%)

3.08 hits per line

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

15.96
/lib/Db/CrlMapper.php
1
<?php
2

3
declare(strict_types=1);
4

5
/**
6
 * SPDX-FileCopyrightText: 2025 LibreCode coop and contributors
7
 * SPDX-License-Identifier: AGPL-3.0-or-later
8
 */
9

10
namespace OCA\Libresign\Db;
11

12
use DateTime;
13
use OCA\Libresign\Enum\CRLReason;
14
use OCA\Libresign\Enum\CRLStatus;
15
use OCP\AppFramework\Db\DoesNotExistException;
16
use OCP\AppFramework\Db\QBMapper;
17
use OCP\DB\QueryBuilder\IQueryBuilder;
18
use OCP\IDBConnection;
19

20
/**
21
 * @template-extends QBMapper<Crl>
22
 */
23
class CrlMapper extends QBMapper {
24
        public function __construct(IDBConnection $db) {
25
                parent::__construct($db, 'libresign_crl');
56✔
26
        }
27

28
        public function findBySerialNumber(string $serialNumber): Crl {
29
                $qb = $this->db->getQueryBuilder();
3✔
30

31
                $qb->select('*')
3✔
32
                        ->from($this->getTableName())
3✔
33
                        ->where($qb->expr()->eq('serial_number', $qb->createNamedParameter($serialNumber)));
3✔
34

35
                /** @var Crl */
36
                return $this->findEntity($qb);
3✔
37
        }
38

39
        public function createCertificate(
40
                string $serialNumber,
41
                string $owner,
42
                string $engine,
43
                string $instanceId,
44
                DateTime $issuedAt,
45
                ?DateTime $validTo = null,
46
        ): Crl {
47
                $certificate = new Crl();
14✔
48
                $certificate->setSerialNumber($serialNumber);
14✔
49
                $certificate->setOwner($owner);
14✔
50
                $certificate->setStatus(CRLStatus::ISSUED);
14✔
51
                $certificate->setIssuedAt($issuedAt);
14✔
52
                $certificate->setValidTo($validTo);
14✔
53
                $certificate->setEngine($engine);
14✔
54
                $certificate->setInstanceId($instanceId);
14✔
55

56
                /** @var Crl */
57
                return $this->insert($certificate);
14✔
58
        }
59

60
        public function revokeCertificate(
61
                string $serialNumber,
62
                CRLReason $reason = CRLReason::UNSPECIFIED,
63
                ?string $comment = null,
64
                ?string $revokedBy = null,
65
                ?DateTime $invalidityDate = null,
66
                ?int $crlNumber = null,
67
        ): Crl {
68
                $certificate = $this->findBySerialNumber($serialNumber);
×
69

70
                if (CRLStatus::from($certificate->getStatus()) !== CRLStatus::ISSUED) {
×
71
                        throw new \InvalidArgumentException('Certificate is not in issued status');
×
72
                }
73

74
                $certificate->setStatus(CRLStatus::REVOKED);
×
75
                $certificate->setReasonCode($reason->value);
×
76
                $certificate->setComment($comment);
×
77
                $certificate->setRevokedBy($revokedBy);
×
78
                $certificate->setRevokedAt(new DateTime());
×
79
                $certificate->setInvalidityDate($invalidityDate);
×
80
                $certificate->setCrlNumber($crlNumber);
×
81

82
                /** @var Crl */
83
                return $this->update($certificate);
×
84
        }
85

86
        public function getRevokedCertificates(string $instanceId = '', int $generation = 0, string $engineType = ''): array {
87
                $qb = $this->db->getQueryBuilder();
×
88

89
                $qb->select('*')
×
90
                        ->from($this->getTableName())
×
91
                        ->where($qb->expr()->eq('status', $qb->createNamedParameter(CRLStatus::REVOKED->value)))
×
92
                        ->orderBy('revoked_at', 'DESC');
×
93

NEW
94
                if ($instanceId !== '') {
×
NEW
95
                        $qb->andWhere($qb->expr()->eq('instance_id', $qb->createNamedParameter($instanceId)));
×
96
                }
NEW
97
                if ($generation !== 0) {
×
NEW
98
                        $qb->andWhere($qb->expr()->eq('generation', $qb->createNamedParameter($generation, IQueryBuilder::PARAM_INT)));
×
99
                }
NEW
100
                if ($engineType !== '') {
×
NEW
101
                        $engineName = match($engineType) {
×
NEW
102
                                'o' => 'openssl',
×
NEW
103
                                'c' => 'cfssl',
×
NEW
104
                                'openssl', 'cfssl' => $engineType,
×
NEW
105
                                default => throw new \InvalidArgumentException("Invalid engine type: $engineType"),
×
NEW
106
                        };
×
NEW
107
                        $qb->andWhere($qb->expr()->eq('engine', $qb->createNamedParameter($engineName)));
×
108
                }
109

110
                return $this->findEntities($qb);
×
111
        }
112

113
        public function isInvalidAt(string $serialNumber, ?DateTime $checkDate = null): bool {
114
                $checkDate = $checkDate ?? new DateTime();
×
115

116
                try {
117
                        $certificate = $this->findBySerialNumber($serialNumber);
×
118
                } catch (DoesNotExistException $e) {
×
119
                        return false;
×
120
                }
121

122
                if ($certificate->isRevoked()) {
×
123
                        return true;
×
124
                }
125

126
                if ($certificate->getInvalidityDate() && $certificate->getInvalidityDate() <= $checkDate) {
×
127
                        return true;
×
128
                }
129

130
                return false;
×
131
        }
132

133
        public function getNextCrlNumber(): int {
134
                $qb = $this->db->getQueryBuilder();
×
135

136
                $result = $qb->select($qb->func()->max('crl_number'))
×
137
                        ->from($this->getTableName())
×
138
                        ->executeQuery();
×
139

140
                $maxCrlNumber = $result->fetchOne();
×
141
                $result->closeCursor();
×
142

143
                return ($maxCrlNumber ?? 0) + 1;
×
144
        }
145

146
        public function cleanupExpiredCertificates(?DateTime $before = null): int {
147
                $before = $before ?? new DateTime('-1 year');
×
148

149
                $qb = $this->db->getQueryBuilder();
×
150

151
                return $qb->delete($this->getTableName())
×
152
                        ->where($qb->expr()->isNotNull('valid_to'))
×
153
                        ->andWhere($qb->expr()->lt('valid_to', $qb->createNamedParameter($before, 'datetime')))
×
154
                        ->executeStatement();
×
155
        }
156

157
        public function getStatistics(): array {
158
                $qb = $this->db->getQueryBuilder();
×
159

160
                $result = $qb->select('status', $qb->func()->count('*', 'count'))
×
161
                        ->from($this->getTableName())
×
162
                        ->groupBy('status')
×
163
                        ->executeQuery();
×
164

165
                $stats = [];
×
166
                while ($row = $result->fetch()) {
×
167
                        $stats[$row['status']] = (int)$row['count'];
×
168
                }
169

170
                $result->closeCursor();
×
171
                return $stats;
×
172
        }
173

174
        public function getRevocationStatistics(): array {
175
                $qb = $this->db->getQueryBuilder();
×
176

177
                $result = $qb->select('reason_code', $qb->func()->count('*', 'count'))
×
178
                        ->from($this->getTableName())
×
179
                        ->where($qb->expr()->eq('status', $qb->createNamedParameter(CRLStatus::REVOKED->value)))
×
180
                        ->andWhere($qb->expr()->isNotNull('reason_code'))
×
181
                        ->groupBy('reason_code')
×
182
                        ->executeQuery();
×
183

184
                $stats = [];
×
185
                while ($row = $result->fetch()) {
×
186
                        $reasonCode = (int)$row['reason_code'];
×
187
                        $reason = CRLReason::tryFrom($reasonCode);
×
188
                        $stats[$reasonCode] = [
×
189
                                'code' => $reasonCode,
×
190
                                'description' => $reason?->getDescription() ?? 'unknown',
×
191
                                'count' => (int)$row['count'],
×
192
                        ];
×
193
                }
194

195
                $result->closeCursor();
×
196
                return $stats;
×
197
        }
198
}
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