Completed
Push — develop ( 146f3e...4146c2 )
by Chris
03:08
created

ComodoDecodeCSR   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 165
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 4

Test Coverage

Coverage 100%

Importance

Changes 18
Bugs 2 Features 8
Metric Value
wmc 19
c 18
b 2
f 8
lcom 2
cbo 4
dl 0
loc 165
ccs 68
cts 68
cp 1
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A getCN() 0 5 1
A setCSR() 0 6 1
A addWarning() 0 6 1
A fetchHashes() 0 10 1
A checkInstalled() 0 16 2
A generateDVC() 0 7 1
C checkDVC() 0 36 7
A decodeCSR() 0 12 1
A processResponse() 0 21 4
1
<?php
2
/**
3
 * @author     Chris Hilsdon <[email protected]>
4
 * @package    ComodoDecodeCSR
5
 * @copyright  2016 Xigen
6
 * @license    GNU General Public License v3
7
 * @link       https://github.com/XigenChris/ComodoDecodeCSR
8
 */
9
10
namespace Xigen;
11
12
use GuzzleHttp\Client;
13
use GuzzleHttp\Exception\ClientException;
14
use GuzzleHttp\Psr7\Response;
15
16
class ComodoDecodeCSR
17
{
18
    use Traits\GetSetUnset;
19
20
    protected $MD5;
21
    protected $SHA1;
22
    protected $Endpoint = "https://secure.comodo.net/products/!decodeCSR";
23
    protected $CSR;
24
    /**
25
     * An array of warnings that can be show after the test
26
     * @var array
27
     */
28
    protected $warnings = [];
29
    protected $Form = [
30
        'responseFormat' => 'N',
31
        'showErrorCodes' => 'N',
32
        'showErrorMessages' => 'N',
33
        'showFieldNames' => 'N',
34
        'showEmptyFields' => 'N',
35
        'showCN' => 'N',
36
        'showAddress' => 'N',
37
        'showPublicKey' => 'N',
38
        'showKeySize' => 'N',
39
        'showSANDNSNames' => 'Y',
40
        'showCSR' => 'N',
41
        'showCSRHashes' => 'Y',
42
        'showSignatureAlgorithm' => 'N',
43
        'product' => '',
44
        'countryNameType' => 'TWOCHAR'
45
    ];
46
    private $request;
47
48 2
    public function getCN()
49
    {
50 2
        $CSRInfo = $this->decodeCSR();
51 2
        return $CSRInfo['subject']['CN'];
52
    }
53
54 10
    public function setCSR($CSR)
55
    {
56
        //TODO Check that this is a valid CSR
57 10
        $this->CSR = $CSR;
58 10
        $this->Form['csr'] = $CSR;
59 10
    }
60
61 11
    protected function addWarning($code, $message)
62
    {
63 1
        $this->warnings[] = [
64
            $code => $message
65 11
        ];
66 1
    }
67
68 10
    public function fetchHashes()
69
    {
70 10
        $client = new Client();
71
72 10
        $this->request = $client->request('POST', $this->getEndpoint(), [
73 10
            'form_params' => $this->Form
74 10
        ]);
75
76 10
        return $this->processResponse();
77
    }
78
79 2
    public function checkInstalled()
80
    {
81 2
        $domain = $this->getCN();
82
        //We do most of our DVC over http:// unless the site is fully SSL
83 2
        $URL = 'http://' . $domain . "/" . $this->getMD5() . '.txt';
84
85 2
        $client = new Client(['allow_redirects' => false, 'verify' => false]);
86
87
        try {
88 2
            $response = $client->request('GET', $URL);
89 2
        } catch (ClientException $e) {
90 1
            return false;
91
        }
92
93 1
        return $this->checkDVC($response);
0 ignored issues
show
Compatibility introduced by
$response of type object<Psr\Http\Message\ResponseInterface> is not a sub-type of object<GuzzleHttp\Psr7\Response>. It seems like you assume a concrete implementation of the interface Psr\Http\Message\ResponseInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
94
    }
95
96 9
    public function generateDVC()
97
    {
98 9
        $DVC = $this->getSHA1() . "\n";
99 9
        $DVC .= "comodoca.com\n";
100
101 9
        return $DVC;
102
    }
103
104
    /**
105
     *
106
     * @param  GuzzleHttp\Psr7\Response $response
107
     * @return bool
108
     */
109 11
    public function checkDVC(Response $response)
110
    {
111 9
        $body = $response->getBody() . '';
112 9
        $DVC = $this->generateDVC();
113
114
        //Check if we received a 301 or 302 redirect
115 9
        if ($response->getStatusCode() === 301 || $response->getStatusCode() == 301) {
116 1
            $message = 'There is a redirect inplace. Make sure that its not redirecting to https://';
117 1
            $this->addWarning(301, $message);
118
119 1
            return false;
120
        }
121
122
        //If the response matches the DVC value return true
123 8
        if ($body === $DVC) {
124 2
            return true;
125
        }
126
127
        //Check if last 2 characters are new lines
128 11
        if (substr($body, -2) === "\n\n") {
129 1
            $body = substr($body, 0, -2) . "\n";
130 1
        }
131
132
        //Check if last character is not a new line
133 6
        if (substr($body, -1) !== "\n") {
134
            //Add said new line
135 3
            $body = $body . "\n";
136 3
        }
137
138
        //Check it again
139 6
        if ($body === $DVC) {
140 2
            return true;
141
        }
142
143 4
        return false;
144
    }
145
146 2
    private function decodeCSR()
147
    {
148 2
        $data = openssl_csr_get_public_key($this->getCSR());
149 2
        $details = openssl_pkey_get_details($data);
150 2
        $key = $details['key'];
151 2
        $subject = openssl_csr_get_subject($this->getCSR());
152
153
        return array(
154 2
            "subject" => $subject,
155
            "key" => $key
156 2
        );
157
    }
158
159 10
    private function processResponse()
160
    {
161 10
        $response = $this->request->getBody();
162 10
        $lines = explode("\n", $response);
163 10
        $data = array();
164
        //Remove the first array as we don't need the SAN and can cause problems
165
        //with a multi domain SAN
166 10
        unset($lines[0]);
167
168 10
        foreach ($lines as $v) {
169 10
            if (!empty($v)) {
170 10
                $value = explode("=", $v);
171 10
                $data[$value[0]] = $value[1];
172 10
            }
173 10
        }
174
175 10
        $this->setMD5($data["md5"]);
176 10
        $this->setSHA1($data["sha1"]);
177
178 10
        return $data ? $data : false;
179
    }
180
}
181