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

LibreSign / libresign / 19745835717

27 Nov 2025 07:06PM UTC coverage: 40.175%. First build
19745835717

Pull #5837

github

web-flow
Merge 54cd86f6b into 161dabcbd
Pull Request #5837: feat: revoke cert when delete account

47 of 57 new or added lines in 5 files covered. (82.46%)

4825 of 12010 relevant lines covered (40.17%)

3.48 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
        ) {
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 {
62
                $filter = array_filter([
×
63
                        'status' => $status,
×
64
                        'engine' => $engine,
×
65
                        'instance_id' => $instanceId,
×
66
                        'generation' => $generation,
×
67
                        'owner' => $owner,
×
68
                        'serial_number' => $serialNumber,
×
69
                        'revoked_by' => $revokedBy,
×
70
                ], fn ($value) => $value !== null);
×
71

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

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

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 {
100
                if (empty($serialNumber)) {
×
101
                        return new DataResponse([
×
102
                                'success' => false,
×
103
                                'message' => 'Serial number is required',
×
104
                        ], Http::STATUS_BAD_REQUEST);
×
105
                }
106

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

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

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

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