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

LibreSign / libresign / 24083625942

07 Apr 2026 01:22PM UTC coverage: 55.6%. First build
24083625942

Pull #7450

github

web-flow
Merge b1c2ec824 into 1112b1165
Pull Request #7450: chore(rector): apply safe test-only batch and php82 baseline

25 of 50 new or added lines in 15 files covered. (50.0%)

10231 of 18401 relevant lines covered (55.6%)

6.61 hits per line

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

75.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\Crl\CrlService;
14
use OCP\AppFramework\Http;
15
use OCP\AppFramework\Http\Attribute\ApiRoute;
16
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
17
use OCP\AppFramework\Http\DataResponse;
18
use OCP\IRequest;
19
use OCP\IUserSession;
20

21
/**
22
 * @psalm-import-type LibresignCrlListResponse from \OCA\Libresign\ResponseDefinitions
23
 * @psalm-import-type LibresignCrlRevokeResponse from \OCA\Libresign\ResponseDefinitions
24
 */
25
class CrlApiController extends AEnvironmentAwareController {
26
        public function __construct(
27
                string $appName,
28
                IRequest $request,
29
                private CrlService $crlService,
30
                private IUserSession $userSession,
31
        ) {
32
                parent::__construct($appName, $request);
10✔
33
        }
34

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

78
                $sort = [];
5✔
79
                if ($sortBy !== null) {
5✔
80
                        $sort[$sortBy] = $sortOrder ?? 'DESC';
1✔
81
                }
82

83
                $result = $this->crlService->listCrlEntries($page, $length, $filter, $sort);
5✔
84

85
                return new DataResponse($result);
5✔
86
        }
87

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

114
                // Use default reason code if not provided
115
                if ($reasonCode === null) {
4✔
116
                        $reasonCode = 0; // Unspecified
1✔
117
                }
118

119
                $reason = CRLReason::tryFrom($reasonCode);
4✔
120
                if ($reason === null) {
4✔
121
                        return new DataResponse([
1✔
122
                                'success' => false,
1✔
123
                                'message' => "Invalid reason code: {$reasonCode}. Must be between 0-10 (excluding 7).",
1✔
124
                        ], Http::STATUS_BAD_REQUEST);
1✔
125
                }
126
                assert($reason instanceof CRLReason);
3✔
127

128
                $user = $this->userSession->getUser();
3✔
129
                $revokedBy = $user ? $user->getUID() : 'system';
3✔
130

131
                try {
132
                        $success = $this->crlService->revokeCertificate(
3✔
133
                                $serialNumber,
3✔
134
                                $reason,
3✔
135
                                $reasonText,
3✔
136
                                $revokedBy
3✔
137
                        );
3✔
138

139
                        if ($success) {
3✔
140
                                return new DataResponse([
×
141
                                        'success' => true,
×
142
                                        'message' => 'Certificate revoked successfully',
×
143
                                ]);
×
144
                        } else {
145
                                return new DataResponse([
3✔
146
                                        'success' => false,
3✔
147
                                        'message' => 'Failed to revoke certificate. It may not exist or already be revoked.',
3✔
148
                                ], Http::STATUS_NOT_FOUND);
3✔
149
                        }
150
                } catch (\InvalidArgumentException $e) {
×
151
                        return new DataResponse([
×
152
                                'success' => false,
×
153
                                'message' => $e->getMessage(),
×
154
                        ], Http::STATUS_BAD_REQUEST);
×
NEW
155
                } catch (\Exception) {
×
156
                        return new DataResponse([
×
157
                                'success' => false,
×
158
                                'message' => 'An error occurred while revoking the certificate',
×
159
                        ], Http::STATUS_BAD_REQUEST);
×
160
                }
161
        }
162
}
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