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

LibreSign / libresign / 19722922474

27 Nov 2025 02:06AM UTC coverage: 39.9%. First build
19722922474

Pull #5828

github

web-flow
Merge 6d6bc1a4f into ec6572ee5
Pull Request #5828: feat: crl manager

0 of 142 new or added lines in 3 files covered. (0.0%)

4772 of 11960 relevant lines covered (39.9%)

3.47 hits per line

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

0.0
/lib/Controller/CrlApiController.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\Controller;
11

12
use OCA\Libresign\Enum\CRLReason;
13
use OCA\Libresign\Service\CrlService;
14
use OCP\AppFramework\Http;
15
use OCP\AppFramework\Http\Attribute\ApiRoute;
16
use OCP\AppFramework\Http\DataResponse;
17
use OCP\IRequest;
18
use OCP\IUserSession;
19

20
class CrlApiController extends AEnvironmentAwareController {
21
        public function __construct(
22
                string $appName,
23
                IRequest $request,
24
                private CrlService $crlService,
25
                private IUserSession $userSession,
26
        ) {
NEW
27
                parent::__construct($appName, $request);
×
28
        }
29

30
        /**
31
         * List CRL entries with pagination and filters
32
         *
33
         * @param int|null $page Page number (1-based)
34
         * @param int|null $length Number of items per page
35
         * @param string|null $status Filter by status (issued, revoked, expired)
36
         * @param string|null $engine Filter by engine type
37
         * @param string|null $instanceId Filter by instance ID
38
         * @param int|null $generation Filter by generation
39
         * @param string|null $owner Filter by owner
40
         * @param string|null $serialNumber Filter by serial number (partial match)
41
         * @param string|null $revokedBy Filter by who revoked the certificate
42
         * @param string|null $sortBy Sort field (e.g., 'revoked_at', 'issued_at', 'serial_number')
43
         * @param string|null $sortOrder Sort order (ASC or DESC)
44
         * @return DataResponse<Http::STATUS_OK, array{data: array<string, mixed>, total: int, page: int, length: int}, array{}>
45
         *
46
         * 200: CRL entries retrieved successfully
47
         */
48
        #[ApiRoute(verb: 'GET', url: '/api/{apiVersion}/crl/list', requirements: ['apiVersion' => '(v1)'])]
49
        public function list(
50
                ?int $page = null,
51
                ?int $length = null,
52
                ?string $status = null,
53
                ?string $engine = null,
54
                ?string $instanceId = null,
55
                ?int $generation = null,
56
                ?string $owner = null,
57
                ?string $serialNumber = null,
58
                ?string $revokedBy = null,
59
                ?string $sortBy = null,
60
                ?string $sortOrder = null,
61
        ): DataResponse {
NEW
62
                $filter = array_filter([
×
NEW
63
                        'status' => $status,
×
NEW
64
                        'engine' => $engine,
×
NEW
65
                        'instance_id' => $instanceId,
×
NEW
66
                        'generation' => $generation,
×
NEW
67
                        'owner' => $owner,
×
NEW
68
                        'serial_number' => $serialNumber,
×
NEW
69
                        'revoked_by' => $revokedBy,
×
NEW
70
                ], fn ($value) => $value !== null);
×
71

NEW
72
                $sort = [];
×
NEW
73
                if ($sortBy !== null) {
×
NEW
74
                        $sort[$sortBy] = $sortOrder ?? 'DESC';
×
75
                }
76

NEW
77
                $result = $this->crlService->listCrlEntries($page, $length, $filter, $sort);
×
78

NEW
79
                return new DataResponse($result);
×
80
        }
81

82
        /**
83
         * Revoke a certificate by serial number
84
         *
85
         * @param string $serialNumber Certificate serial number to revoke
86
         * @param int|null $reasonCode Revocation reason code (0-10, see RFC 5280)
87
         * @param string|null $reasonText Optional text describing the reason
88
         * @return DataResponse<Http::STATUS_OK, array{success: bool, message: string}, array{}>|DataResponse<Http::STATUS_BAD_REQUEST, array{success: bool, message: string}, array{}>|DataResponse<Http::STATUS_NOT_FOUND, array{success: bool, message: string}, array{}>
89
         *
90
         * 200: Certificate revoked successfully
91
         * 400: Invalid parameters
92
         * 404: Certificate not found
93
         */
94
        #[ApiRoute(verb: 'POST', url: '/api/{apiVersion}/crl/revoke', requirements: ['apiVersion' => '(v1)'])]
95
        public function revoke(
96
                string $serialNumber,
97
                ?int $reasonCode = null,
98
                ?string $reasonText = null,
99
        ): DataResponse {
NEW
100
                if (empty($serialNumber)) {
×
NEW
101
                        return new DataResponse([
×
NEW
102
                                'success' => false,
×
NEW
103
                                'message' => 'Serial number is required',
×
NEW
104
                        ], Http::STATUS_BAD_REQUEST);
×
105
                }
106

NEW
107
                $reasonCode = $reasonCode ?? CRLReason::UNSPECIFIED->value;
×
108

NEW
109
                if (!CRLReason::isValid($reasonCode)) {
×
NEW
110
                        return new DataResponse([
×
NEW
111
                                'success' => false,
×
NEW
112
                                'message' => "Invalid reason code: {$reasonCode}. Must be between 0-10 (excluding 7).",
×
NEW
113
                        ], Http::STATUS_BAD_REQUEST);
×
114
                }
115

NEW
116
                $user = $this->userSession->getUser();
×
NEW
117
                $revokedBy = $user ? $user->getUID() : 'system';
×
118

119
                try {
NEW
120
                        $success = $this->crlService->revokeCertificate(
×
NEW
121
                                $serialNumber,
×
NEW
122
                                $reasonCode,
×
NEW
123
                                $reasonText,
×
NEW
124
                                $revokedBy
×
NEW
125
                        );
×
126

NEW
127
                        if ($success) {
×
NEW
128
                                return new DataResponse([
×
NEW
129
                                        'success' => true,
×
NEW
130
                                        'message' => 'Certificate revoked successfully',
×
NEW
131
                                ]);
×
132
                        } else {
NEW
133
                                return new DataResponse([
×
NEW
134
                                        'success' => false,
×
NEW
135
                                        'message' => 'Failed to revoke certificate. It may not exist or already be revoked.',
×
NEW
136
                                ], Http::STATUS_NOT_FOUND);
×
137
                        }
NEW
138
                } catch (\InvalidArgumentException $e) {
×
NEW
139
                        return new DataResponse([
×
NEW
140
                                'success' => false,
×
NEW
141
                                'message' => $e->getMessage(),
×
NEW
142
                        ], Http::STATUS_BAD_REQUEST);
×
NEW
143
                } catch (\Exception $e) {
×
NEW
144
                        return new DataResponse([
×
NEW
145
                                'success' => false,
×
NEW
146
                                'message' => 'An error occurred while revoking the certificate',
×
NEW
147
                        ], Http::STATUS_BAD_REQUEST);
×
148
                }
149
        }
150
}
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