Issues (41)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

source/Threema/MsgApi/Connection.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * @author Threema GmbH
4
 * @copyright Copyright (c) 2015-2016 Threema GmbH
5
 */
6
7
8
namespace Threema\MsgApi;
9
10
use Threema\Core\Exception;
11
use Threema\Core\Url;
12
use Threema\MsgApi\Commands\Capability;
13
use Threema\MsgApi\Commands\CommandInterface;
14
use Threema\MsgApi\Commands\Credits;
15
use Threema\MsgApi\Commands\DownloadFile;
16
use Threema\MsgApi\Commands\FetchPublicKey;
17
use Threema\MsgApi\Commands\LookupEmail;
18
use Threema\MsgApi\Commands\LookupPhone;
19
use Threema\MsgApi\Commands\MultiPartCommandInterface;
20
use Threema\MsgApi\Commands\Results\CapabilityResult;
21
use Threema\MsgApi\Commands\Results\DownloadFileResult;
22
use Threema\MsgApi\Commands\Results\FetchPublicKeyResult;
23
use Threema\MsgApi\Commands\Results\LookupIdResult;
24
use Threema\MsgApi\Commands\Results\Result;
25
use Threema\MsgApi\Commands\Results\SendSimpleResult;
26
use Threema\MsgApi\Commands\Results\SendE2EResult;
27
use Threema\MsgApi\Commands\Results\UploadFileResult;
28
use Threema\MsgApi\Commands\SendSimple;
29
use Threema\MsgApi\Commands\SendE2E;
30
use Threema\MsgApi\Commands\UploadFile;
31
use Threema\MsgApi\Constants;
32
33
/**
34
 * Class Connection
35
 * @package Threema\MsgApi
36
 */
37
class Connection
38
{
39
	/**
40
	 * @var ConnectionSettings
41
	 */
42
	private $setting;
43
44
	/**
45
	 * @var PublicKeyStore
46
	 */
47
	private $publicKeyStore;
48
49
	/**
50
	 * @param ConnectionSettings $setting
51
	 * @param PublicKeyStore $publicKeyStore stores the public keys locally to save network traffic
52
	 */
53
	public function __construct(ConnectionSettings $setting, PublicKeyStore $publicKeyStore = null) {
54
		$this->setting = $setting;
55
		$this->publicKeyStore = $publicKeyStore;
56
	}
57
58
	/**
59
	 * @param Receiver $receiver
60
	 * @param $text
61
	 * @return SendSimpleResult
62
	 */
63
	public function sendSimple(Receiver $receiver, $text) {
64
		$command = new SendSimple($receiver, $text);
65
		return $this->post($command);
66
	}
67
68
	/**
69
	 * @param string $threemaId
70
	 * @param string $nonce
71
	 * @param string $box
72
	 * @return SendE2EResult
73
	 */
74
	public function sendE2E($threemaId, $nonce, $box) {
75
		$command = new SendE2E($threemaId, $nonce, $box);
76
		return $this->post($command);
77
	}
78
79
	/**
80
	 * @param $encryptedFileData (binary string)
81
	 * @return UploadFileResult
82
	 */
83
	public function uploadFile($encryptedFileData) {
84
		$command = new UploadFile($encryptedFileData);
85
		return $this->postMultiPart($command);
86
	}
87
88
89
	/**
90
	 * @param $blobId
91
	 * @param callable $progress
92
	 * @return DownloadFileResult
93
	 */
94
	public function downloadFile($blobId, \Closure $progress = null) {
95
		$command = new DownloadFile($blobId);
96
		return $this->get($command, $progress);
97
	}
98
99
	/**
100
	 * @param $phoneNumber
101
	 * @return LookupIdResult
102
	 */
103
	public function keyLookupByPhoneNumber($phoneNumber) {
104
		$command = new LookupPhone($phoneNumber);
105
		return $this->get($command);
106
	}
107
108
	/**
109
	 * @param string $email
110
	 * @return LookupIdResult
111
	 */
112
	public function keyLookupByEmail($email) {
113
		$command = new LookupEmail($email);
114
		return $this->get($command);
115
	}
116
117
	/**
118
	 * @param string $threemaId valid threema id (8 Chars)
119
	 * @return CapabilityResult
120
	 */
121
	public function keyCapability($threemaId) {
122
		return $this->get(new Capability($threemaId));
123
	}
124
125
126
	/**
127
	 * @return CreditsResult
128
	 */
129
	public function credits() {
130
		return $this->get(new Credits());
131
	}
132
133
	/**
134
	 * @param $threemaId
135
	 * @return FetchPublicKeyResult
136
	 */
137
	public function fetchPublicKey($threemaId) {
138
		$publicKey = null;
139
140
		if (null !== $this->publicKeyStore) {
141
			$publicKey = $this->publicKeyStore->getPublicKey($threemaId);
142
		}
143
144
		if (null === $publicKey) {
145
			$command = new FetchPublicKey($threemaId);
146
			$result = $this->get($command);
147
			if (false === $result->isSuccess()) {
148
				return $result;
149
			}
150
			$publicKey = $result->getRawResponse();
151
152
			if (null !== $this->publicKeyStore) {
153
				$this->publicKeyStore->setPublicKey($threemaId, $publicKey);
154
			}
155
		}
156
157
		//create a key result
158
		return new FetchPublicKeyResult(200, $publicKey);
159
	}
160
161
	/**
162
	 * @param callable $progress
163
	 * @return array
164
	 */
165
	private function createDefaultOptions(\Closure $progress = null) {
166
		$options = array(
167
			CURLOPT_RETURNTRANSFER => true
168
		);
169
170
		//no progress
171
		if (null !== $progress) {
172
			$options[CURLOPT_NOPROGRESS] = false;
173
			$options[CURLOPT_PROGRESSFUNCTION] = $progress;
174
		}
175
176
		//tls settings
177
178
		if (true === $this->setting->getTlsOption(ConnectionSettings::tlsOptionForceHttps, false)) {
179
			//limit allowed protocols to HTTPS
180
			$options[CURLOPT_PROTOCOLS] = CURLPROTO_HTTPS;
181
		}
182
		if ($tlsVersion = $this->setting->getTlsOption(ConnectionSettings::tlsOptionVersion)) {
183
			if (is_int($tlsVersion)) {
184
				//if number is given use it
185
				$options[CURLOPT_SSLVERSION] = $tlsVersion;
186
			} else {
187
				//interpret strings as TLS versions
188
				switch ($tlsVersion) {
189
					case '1.0':
190
						$options[CURLOPT_SSLVERSION] = CURL_SSLVERSION_TLSv1_0;
191
						break;
192
					case '1.1':
193
						$options[CURLOPT_SSLVERSION] = CURL_SSLVERSION_TLSv1_1;
194
						break;
195
					case '1.2':
196
						$options[CURLOPT_SSLVERSION] = CURL_SSLVERSION_TLSv1_2;
197
						break;
198
					default:
199
						$options[CURLOPT_SSLVERSION] = CURL_SSLVERSION_DEFAULT;
200
						break;
201
				}
202
			}
203
		}
204 View Code Duplication
		if ($tlsCipher = $this->setting->getTlsOption(ConnectionSettings::tlsOptionCipher, null)) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
205
			if(true === is_string($tlsCipher)) {
206
				$options[CURLOPT_SSL_CIPHER_LIST] = $tlsCipher;
207
			}
208
		}
209 View Code Duplication
		if ($pinnedKey = $this->setting->getTlsOption(ConnectionSettings::tlsOptionPinnedKey, Constants::DEFAULT_PINNED_KEY)) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
210
			if(true === is_string($pinnedKey)) {
211
				$options[CURLOPT_PINNEDPUBLICKEY] = $pinnedKey;
212
			}
213
		}
214
		return $options;
215
	}
216
217
	/**
218
	 * @param array $params
219
	 * @return array
220
	 */
221
	private function processRequestParams(array $params) {
222
		if (null === $params) {
223
			$params = array();
224
		}
225
226
		$params['from'] = $this->setting->getThreemaId();
227
		$params['secret'] = $this->setting->getSecret();
228
229
		return $params;
230
	}
231
232
	/**
233
	 * @param CommandInterface $command
234
	 * @param callable $progress
235
	 * @return Result
236
	 */
237
	protected function get(CommandInterface $command, \Closure $progress = null) {
238
		$params = $this->processRequestParams($command->getParams());
239
		return $this->call($command->getPath(),
240
			$this->createDefaultOptions($progress),
241
			$params,
242
			function ($httpCode, $response) use ($command) {
243
				return $command->parseResult($httpCode, $response);
244
			});
245
	}
246
247
	/**
248
	 * @param CommandInterface $command
249
	 * @return Result
250
	 */
251
	protected function post(CommandInterface $command) {
252
		$options = $this->createDefaultOptions();
253
		$params = $this->processRequestParams($command->getParams());
254
255
		$options[CURLOPT_POST] = true;
256
		$options[CURLOPT_POSTFIELDS] = http_build_query($params);
257
		$options[CURLOPT_HTTPHEADER] = array(
258
			'Content-Type: application/x-www-form-urlencoded');
259
260
		return $this->call($command->getPath(), $options, null, function ($httpCode, $response) use ($command) {
261
			return $command->parseResult($httpCode, $response);
262
		});
263
	}
264
265
	/**
266
	 * @param MultiPartCommandInterface $command
267
	 * @return Result
268
	 */
269
	protected function postMultiPart(MultiPartCommandInterface $command) {
270
		$options = $this->createDefaultOptions();
271
		$params = $this->processRequestParams($command->getParams());
272
273
		$options[CURLOPT_POST] = true;
274
		$options[CURLOPT_HTTPHEADER] = array('Content-Type: multipart/form-data');
275
		$options[CURLOPT_SAFE_UPLOAD] = true;
276
		$options[CURLOPT_POSTFIELDS] = array(
277
			'blob' => $command->getData()
278
		);
279
280
		return $this->call($command->getPath(), $options, $params, function ($httpCode, $response) use ($command) {
281
			return $command->parseResult($httpCode, $response);
282
		});
283
	}
284
285
	/**
286
	 * @param string $path
287
	 * @param array $curlOptions
288
	 * @param array $parameters
289
	 * @param callable $result
290
	 * @return mixed
291
	 * @throws \Threema\Core\Exception
292
	 */
293
	private function call($path, array $curlOptions, array $parameters = null, \Closure $result = null) {
294
		$fullPath = new Url('', $this->setting->getHost());
295
		$fullPath->addPath($path);
296
297
		if (null !== $parameters && count($parameters)) {
298
			foreach ($parameters as $key => $value) {
299
				$fullPath->setValue($key, $value);
300
			}
301
		}
302
		$session = curl_init($fullPath->getFullPath());
303
		curl_setopt_array($session, $curlOptions);
304
305
		$response = curl_exec($session);
306
		if (false === $response) {
307
			throw new Exception($path . ' ' . curl_error($session));
308
		}
309
310
		$httpCode = curl_getinfo($session, CURLINFO_HTTP_CODE);
311
		if (null === $result && $httpCode != 200) {
312
			throw new Exception($httpCode);
313
		}
314
315
		if (null !== $result) {
316
			return $result->__invoke($httpCode, $response);
317
		} else {
318
			return $response;
319
		}
320
	}
321
}
322