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

eliashaeussler / cpanel-requests / 12331121675

14 Dec 2024 03:41PM UTC coverage: 99.252% (-0.2%) from 99.497%
12331121675

push

github

web-flow
Merge pull request #237 from eliashaeussler/renovate/major-phpstan-packages

[TASK] Update phpstan/phpstan-phpunit to v2

3 of 4 new or added lines in 1 file covered. (75.0%)

398 of 401 relevant lines covered (99.25%)

9.29 hits per line

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

98.15
/src/Application/Session/WebSession.php
1
<?php
2

3
declare(strict_types=1);
4

5
/*
6
 * This file is part of the Composer package "eliashaeussler/cpanel-requests".
7
 *
8
 * Copyright (C) 2020-2024 Elias Häußler <elias@haeussler.dev>
9
 *
10
 * This program is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation, either version 3 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22
 */
23

24
namespace EliasHaeussler\CpanelRequests\Application\Session;
25

26
use EliasHaeussler\CpanelRequests\Exception;
27
use EliasHaeussler\CpanelRequests\Http;
28
use EliasHaeussler\CpanelRequests\Resource;
29
use GuzzleHttp\Client as GuzzleClient;
30
use GuzzleHttp\Cookie;
31
use GuzzleHttp\Psr7;
32
use GuzzleHttp\RequestOptions;
33
use Psr\Http\Client;
34
use Psr\Http\Message;
35

36
use function is_string;
37

38
/**
39
 * Representation of a web session of a single application.
40
 *
41
 * @author Elias Häußler <elias@haeussler.dev>
42
 * @license GPL-3.0-or-later
43
 */
44
final class WebSession
45
{
46
    private const SESSION_TOKEN_PARAMETER = 'security_token';
47

48
    private bool $active;
49
    private readonly Http\UriBuilder\DefaultUriBuilder $uriBuilder;
50
    private readonly Message\RequestFactoryInterface $requestFactory;
51
    private readonly Http\Response\ResponseFactory $responseFactory;
52
    private readonly GuzzleClient $client;
53
    private readonly Resource\File $cookie;
54
    private ?string $identifier = null;
55

56
    public function __construct(
18✔
57
        private readonly Message\UriInterface $baseUri,
58
    ) {
59
        $this->active = false;
18✔
60
        $this->uriBuilder = new Http\UriBuilder\DefaultUriBuilder();
18✔
61
        $this->requestFactory = new Psr7\HttpFactory();
18✔
62
        $this->responseFactory = new Http\Response\ResponseFactory();
18✔
63
        $this->client = new GuzzleClient();
18✔
64
        $this->cookie = Resource\Cookie::create();
18✔
65
    }
66

67
    /**
68
     * @throws Client\ClientExceptionInterface
69
     * @throws Exception\AuthenticationFailedException
70
     * @throws Exception\InvalidResponseDataException
71
     * @throws Exception\RequestFailedException
72
     */
73
    public function start(string $username, string $password, ?string $otp = null): void
14✔
74
    {
75
        // Build request object
76
        $request = new Http\Request\ApiRequest($this->baseUri, 'login');
14✔
77
        $request->setParameters([
14✔
78
            'login_only' => 1,
14✔
79
            'user' => $username,
14✔
80
            'pass' => $password,
14✔
81
        ]);
14✔
82

83
        if (null !== $otp) {
14✔
84
            $request->addParameter('tfa_token', $otp);
2✔
85
        }
86

87
        // Send authentication request
88
        $uri = $this->uriBuilder->buildUriForRequest($request);
14✔
89
        $response = $this->sendRequest('GET', $uri);
14✔
90

91
        // Throw exception if response is no JSON response
92
        if (!($response instanceof Http\Response\JsonResponse)) {
14✔
93
            throw Exception\RequestFailedException::forUnexpectedResponse(Http\Response\JsonResponse::class, $response);
1✔
94
        }
95

96
        // Throw exception if API response is not valid
97
        if (!$response->isValid(self::SESSION_TOKEN_PARAMETER)) {
13✔
98
            throw Exception\AuthenticationFailedException::create();
1✔
99
        }
100

101
        $identifier = $response->getData()->{self::SESSION_TOKEN_PARAMETER};
12✔
102

103
        // Throw exception if identifier is not valid
104
        if (!is_string($identifier) && null !== $identifier) {
12✔
NEW
105
            throw Exception\SessionException::forInvalidSessionIdentifier();
×
106
        }
107

108
        $this->active = true;
12✔
109
        $this->identifier = $identifier;
12✔
110

111
        $this->validateIdentifier();
12✔
112
    }
113

114
    /**
115
     * @throws Exception\InvalidResponseDataException
116
     * @throws Client\ClientExceptionInterface
117
     */
118
    public function stop(): bool
2✔
119
    {
120
        if (!$this->active) {
2✔
121
            return true;
1✔
122
        }
123

124
        $request = new Http\Request\ApiRequest($this->baseUri, 'logout');
1✔
125
        $uri = $this->uriBuilder->buildUriForRequest($request);
1✔
126
        $response = $this->sendRequest('GET', $uri);
1✔
127

128
        // @codeCoverageIgnoreStart
129
        if ($response->isValid()) {
130
            $this->active = false;
131
        }
132
        // @codeCoverageIgnoreEnd
133

134
        return !$this->active;
1✔
135
    }
136

137
    public function isActive(): bool
12✔
138
    {
139
        return $this->active;
12✔
140
    }
141

142
    public function getCookie(): Resource\File
3✔
143
    {
144
        return $this->cookie;
3✔
145
    }
146

147
    public function getIdentifier(): ?string
10✔
148
    {
149
        return $this->identifier;
10✔
150
    }
151

152
    /**
153
     * @throws Client\ClientExceptionInterface
154
     */
155
    private function sendRequest(string $method, Message\UriInterface $uri): Http\Response\ResponseInterface
14✔
156
    {
157
        // Add cookie file
158
        $cookieJar = new Cookie\FileCookieJar($this->cookie->getPathname(), true);
14✔
159
        $options = [
14✔
160
            RequestOptions::COOKIES => $cookieJar,
14✔
161
        ];
14✔
162

163
        // Send request
164
        $request = $this->requestFactory->createRequest($method, $uri);
14✔
165
        $response = $this->client->send($request, $options);
14✔
166

167
        return $this->responseFactory->createFromResponse($response);
14✔
168
    }
169

170
    private function validateIdentifier(): void
12✔
171
    {
172
        if (null === $this->identifier) {
12✔
173
            throw Exception\SessionException::forInactiveSession();
1✔
174
        }
175
        if ('' === trim($this->identifier)) {
11✔
176
            throw Exception\SessionException::forInvalidSessionIdentifier();
1✔
177
        }
178
    }
179
}
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

© 2025 Coveralls, Inc