Completed
Pull Request — master (#8)
by John
02:04
created

LEClient::__construct()   F

Complexity

Conditions 28
Paths 349

Size

Total Lines 95
Code Lines 53

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 34
CRAP Score 28

Importance

Changes 0
Metric Value
cc 28
eloc 53
c 0
b 0
f 0
nc 349
nop 5
dl 0
loc 95
rs 1.4708
ccs 34
cts 34
cp 1
crap 28

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace LEClient;
4
5
use LEClient\Exceptions\LEClientException;
6
7
/**
8
 * Main LetsEncrypt Client class, works as a framework for the LEConnector, LEAccount, LEOrder and LEAuthorization classes.
9
 *
10
 * PHP version 5.2.0
11
 *
12
 * MIT License
13
 *
14
 * Copyright (c) 2018 Youri van Weegberg
15
 *
16
 * Permission is hereby granted, free of charge, to any person obtaining a copy
17
 * of this software and associated documentation files (the "Software"), to deal
18
 * in the Software without restriction, including without limitation the rights
19
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
20
 * copies of the Software, and to permit persons to whom the Software is
21
 * furnished to do so, subject to the following conditions:
22
 *
23
 * The above copyright notice and this permission notice shall be included in all
24
 * copies or substantial portions of the Software.
25
 *
26
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32
 * SOFTWARE.
33
 *
34
 * @author     Youri van Weegberg <[email protected]>
35
 * @copyright  2018 Youri van Weegberg
36
 * @license    https://opensource.org/licenses/mit-license.php  MIT License
37
 * @link       https://github.com/yourivw/LEClient
38
 * @since      Class available since Release 1.0.0
39
 */
40
class LEClient
41
{
42
	const LE_PRODUCTION = 'https://acme-v02.api.letsencrypt.org';
43
	const LE_STAGING = 'https://acme-staging-v02.api.letsencrypt.org';
44
45
	private $certificateKeys;
46
	private $accountKeys;
47
48
	private $connector;
49
	private $account;
50
51
	private $log;
52
53
	const LOG_OFF = 0;		// Logs no messages or faults, except Runtime Exceptions.
54
	const LOG_STATUS = 1;	// Logs only messages and faults.
55
	const LOG_DEBUG = 2;	// Logs messages, faults and raw responses from HTTP requests.
56
57
    /**
58
     * Initiates the LetsEncrypt main client.
59
     *
60
     * @param array		$email	 			The array of strings containing e-mail addresses. Only used in this function when creating a new account.
61
     * @param boolean	$acmeURL			ACME URL, can be string or one of predefined values: LE_STAGING or LE_PRODUCTION. Defaults to LE_STAGING.
62
     * @param int 		$log				The level of logging. Defaults to no logging. LOG_OFF, LOG_STATUS, LOG_DEBUG accepted. Defaults to LOG_OFF. (optional)
63
     * @param string 	$certificateKeys 	The main directory in which all keys (and certificates), including account keys, are stored. Defaults to 'keys/'. (optional)
64
     * @param array 	$certificateKeys 	Optional array containing location of all certificate files. Required paths are public_key, private_key, order and certificate/fullchain_certificate (you can use both or only one of them)
65
     * @param string 	$accountKeys 		The directory in which the account keys are stored. Is a subdir inside $certificateKeys. Defaults to '__account/'.(optional)
66
     * @param array 	$accountKeys 		Optional array containing location of account private and public keys. Required paths are private_key, public_key.
67
     */
68
	public function __construct($email, $acmeURL = LEClient::LE_PRODUCTION, $log = LEClient::LOG_OFF, $certificateKeys = 'keys/', $accountKeys = '__account/')
69
	{
70
		$this->log = $log;
71
72
		if (is_bool($acmeURL))
73 8
		{
74
			if ($acmeURL === true) $this->baseURL = LEClient::LE_STAGING;
0 ignored issues
show
Bug Best Practice introduced by
The property baseURL does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
75
			elseif ($acmeURL === false) $this->baseURL = LEClient::LE_PRODUCTION;
0 ignored issues
show
introduced by
The condition $acmeURL === false is always true.
Loading history...
76
		}
77
		elseif (is_string($acmeURL))
0 ignored issues
show
introduced by
The condition is_string($acmeURL) is always true.
Loading history...
78
		{
79
			$this->baseURL = $acmeURL;
80
		}
81
		else throw LEClientException::InvalidArgumentException('acmeURL must be set to string or bool (legacy).');
82 8
83
		if (is_array($certificateKeys) && is_string($accountKeys)) throw LEClientException::InvalidArgumentException('When certificateKeys is array, accountKeys must be array too.');
84 8
		elseif (is_array($accountKeys) && is_string($certificateKeys)) throw LEClientException::InvalidArgumentException('When accountKeys is array, certificateKeys must be array too.');
85
86 6
		if (is_string($certificateKeys))
87
		{
88 6
			$certificateKeysDir = $certificateKeys;
89 6
90 6
			if(!file_exists($certificateKeys))
91 6
			{
92 6
				mkdir($certificateKeys, 0755, true);
93 6
				LEFunctions::createhtaccess($certificateKeys);
94
			}
95 8
96
			$this->certificateKeys = array(
97 8
				"public_key" => $certificateKeys.'/public.pem',
98 4
				"private_key" => $certificateKeys.'/private.pem',
99 4
				"certificate" => $certificateKeys.'/certificate.crt',
100 2
				"fullchain_certificate" => $certificateKeys.'/fullchain.crt',
101
				"order" => $certificateKeys.'/order'
102 2
			);
103
		}
104 6
		elseif (is_array($certificateKeys))
0 ignored issues
show
introduced by
The condition is_array($certificateKeys) is always true.
Loading history...
105
		{
106 2
			if (!isset($certificateKeys['certificate']) && !isset($certificateKeys['fullchain_certificate'])) throw LEClientException::InvalidArgumentException('certificateKeys[certificate] or certificateKeys[fullchain_certificate] file path must be set.');
107
			if (!isset($certificateKeys['private_key'])) throw LEClientException::InvalidArgumentException('certificateKeys[private_key] file path must be set.');
108 2
			if (!isset($certificateKeys['order'])) $certificateKeys['order'] = dirname($certificateKeys['private_key']).'/order';
109
			if (!isset($certificateKeys['public_key'])) $certificateKeys['public_key'] = dirname($certificateKeys['private_key']).'/public.pem';
110
111
			foreach ($certificateKeys as $param => $file) {
112
				$parentDir = dirname($file);
113
				if (!is_dir($parentDir)) throw LEClientException::InvalidDirectoryException($parentDir);
114
			}
115 2
116
			$this->certificateKeys = $certificateKeys;
117 2
		}
118 2
		else
119
		{
120
			throw LEClientException::InvalidArgumentException('certificateKeys must be string or array.');
121
		}
122
123
		if (is_string($accountKeys))
124 2
		{
125
			$accountKeys = $certificateKeysDir.'/'.$accountKeys;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $certificateKeysDir does not seem to be defined for all execution paths leading up to this point.
Loading history...
126 2
127 2
			if(!file_exists($accountKeys))
128
			{
129 2
				mkdir($accountKeys, 0755, true);
130
				LEFunctions::createhtaccess($accountKeys);
131 2
			}
132 2
133
			$this->accountKeys = array(
134
				"private_key" => $accountKeys.'/private.pem',
135 2
				"public_key" => $accountKeys.'/public.pem'
136
			);
137
		}
138 2
		elseif (is_array($accountKeys))
0 ignored issues
show
introduced by
The condition is_array($accountKeys) is always true.
Loading history...
139
		{
140
			if (!isset($accountKeys['private_key'])) throw LEClientException::InvalidArgumentException('accountKeys[private_key] file path must be set.');
141
			if (!isset($accountKeys['public_key'])) throw LEClientException::InvalidArgumentException('accountKeys[public_key] file path must be set.');
142
143
			foreach ($accountKeys as $param => $file) {
144
				$parentDir = dirname($file);
145
				if (!is_dir($parentDir)) throw LEClientException::InvalidDirectoryException($parentDir);
146 2
			}
147
148 2
			$this->accountKeys = $accountKeys;
149 2
		}
150
		else
151 2
		{
152
			throw LEClientException::InvalidArgumentException('accountKeys must be string or array.');
153
		}
154
155
		$this->connector = new LEConnector($this->log, $this->baseURL, $this->accountKeys);
156
		$this->account = new LEAccount($this->connector, $this->log, $email, $this->accountKeys);
157
		
158
		if($this->log instanceof \Psr\Log\LoggerInterface) 
0 ignored issues
show
introduced by
$this->log is never a sub-type of Psr\Log\LoggerInterface.
Loading history...
159
		{
160
			$this->log->info('LEClient finished constructing');
161
		}
162
		elseif($this->log >= LEClient::LOG_STATUS) LEFunctions::log('LEClient finished constructing', 'function LEClient __construct');
0 ignored issues
show
Bug introduced by
'LEClient finished constructing' of type string is incompatible with the type object expected by parameter $data of LEClient\LEFunctions::log(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

162
		elseif($this->log >= LEClient::LOG_STATUS) LEFunctions::log(/** @scrutinizer ignore-type */ 'LEClient finished constructing', 'function LEClient __construct');
Loading history...
163
	}
164
165
166
    /**
167
     * Returns the LetsEncrypt account used in the current client.
168
	 *
169
	 * @return LEAccount	The LetsEncrypt Account instance used by the client.
170
     */
171
	public function getAccount()
172 2
	{
173
		return $this->account;
174 2
	}
175
176 2
    /**
177 2
     * Returns a LetsEncrypt order. If an order exists, this one is returned. If not, a new order is created and returned.
178 2
     *
179 2
     * @param string	$basename	The base name for the order. Preferable the top domain (example.org). Will be the directory in which the keys are stored. Used for the CommonName in the certificate as well.
180 2
     * @param array 	$domains 	The array of strings containing the domain names on the certificate.
181 2
     * @param string 	$keyType 	Type of the key we want to use for certificate. Can be provided in ALGO-SIZE format (ex. rsa-4096 or ec-256) or simple "rsa" and "ec" (using default sizes)
182 2
     * @param string 	$notBefore	A date string formatted like 0000-00-00T00:00:00Z (yyyy-mm-dd hh:mm:ss) at which the certificate becomes valid. Defaults to the moment the order is finalized. (optional)
183
     * @param string 	$notAfter  	A date string formatted like 0000-00-00T00:00:00Z (yyyy-mm-dd hh:mm:ss) until which the certificate is valid. Defaults to 90 days past the moment the order is finalized. (optional)
184 2
     *
185
     * @return LEOrder	The LetsEncrypt Order instance which is either retrieved or created.
186 2
     */
187
	public function getOrCreateOrder($basename, $domains, $keyType = 'rsa-4096', $notBefore = '', $notAfter = '')
188
	{
189
		return new LEOrder($this->connector, $this->log, $this->certificateKeys, $basename, $domains, $keyType, $notBefore, $notAfter);
190
	}
191
}
192