ThreemaGateway_Handler_PhpSdk   A
last analyzed

Complexity

Total Complexity 26

Size/Duplication

Total Lines 298
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
wmc 26
lcom 1
cbo 3
dl 0
loc 298
rs 10
c 0
b 0
f 0

14 Methods

Rating   Name   Duplication   Size   Complexity  
A getInstance() 0 8 2
A getVersion() 0 4 1
A getFeatureLevel() 0 4 1
A getConnector() 0 4 1
A getE2EHelper() 0 7 2
A getReceiver() 0 4 1
A getCryptTool() 0 4 1
A getSettings() 0 4 1
A __construct() 0 18 2
A __clone() 0 4 1
B loadLib() 0 24 4
A createKeystore() 0 12 3
A createConnection() 0 16 2
B createConnectionSettings() 0 44 4
1
<?php
2
/**
3
 * Provides the connection to the PHP SDK.
4
 *
5
 * @package ThreemaGateway
6
 * @author rugk
7
 * @copyright Copyright (c) 2015-2016 rugk
8
 * @license MIT
9
 */
10
11
use Threema\MsgApi\Receiver;
12
use Threema\MsgApi\Helpers\E2EHelper;
13
use Threema\MsgApi\Connection;
14
use Threema\MsgApi\ConnectionSettings;
15
16
class ThreemaGateway_Handler_PhpSdk
17
{
18
    /**
19
     * @var Singleton
20
     */
21
    protected static $instance = null;
22
23
    /**
24
     * @var string Path to Threema Gateway PHP SDK
25
     */
26
    protected $sdkDir = __DIR__ . '/../threema-msgapi-sdk-php';
27
28
    /**
29
     * @var ThreemaGateway_Handler_Settings
30
     */
31
    protected $settings;
32
33
    /**
34
     * @var string Version of Threema Gateway PHP SDK
35
     */
36
    protected $sdkVersion;
37
38
    /**
39
     * @var int Feature level of PHP SDK
40
     */
41
    protected $sdkFeatureLevel;
42
43
    /**
44
     * @var Threema\MsgApi\Tools\CryptTool
45
     */
46
    protected $cryptTool;
47
48
    /**
49
     * @var Threema\MsgApi\PublicKeyStore
50
     */
51
    protected $keystore;
52
53
    /**
54
     * @var Threema\MsgApi\Connection The connector to the PHP-SDK
55
     */
56
    protected $connector;
57
58
    /**
59
     * @var E2EHelper The Threema E2E helper, which is necessary when dealing
60
     *                with end-to-end-encrypted messages.
61
     */
62
    protected $e2eHelper;
63
64
    /**
65
     * Initiate PHP-SDK.
66
     *
67
     * @param ThreemaGateway_Handler_Settings|null $settings
68
     * @throws XenForo_Exception
69
     */
70
    protected function __construct($settings = null)
71
    {
72
        // get options
73
        if ($settings !== null) {
74
            $this->settings = $settings;
75
        } else {
76
            $this->settings = new ThreemaGateway_Handler_Settings;
77
        }
78
79
        // load libraries
80
        $this->loadLib();
81
82
        //create keystore
83
        $this->createKeystore();
84
85
        //create connection
86
        $this->createConnection();
87
    }
88
89
    /**
90
     * Prevent cloning for Singleton.
91
     */
92
    protected function __clone()
93
    {
94
        // I smash clones!
95
    }
96
97
    /**
98
     * SDK startup as a Singleton.
99
     *
100
     * @param ThreemaGateway_Handler_Settings If you already used the settings
101
     *                                        you can pass them here, so the
102
     *                                        class can reuse them.
103
     * @param  ThreemaGateway_Handler_Settings $settings
104
     * @throws XenForo_Exception
105
     * @return void
0 ignored issues
show
Documentation introduced by
Should the return type not be ThreemaGateway_Handler_PhpSdk|Singleton?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
106
     */
107
    public static function getInstance($settings = null)
108
    {
109
        if (!isset(self::$instance)) {
110
            self::$instance = new self($settings);
0 ignored issues
show
Documentation Bug introduced by
It seems like new self($settings) of type object<ThreemaGateway_Handler_PhpSdk> is incompatible with the declared type object<Singleton> of property $instance.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
111
        }
112
113
        return self::$instance;
114
    }
115
116
    /**
117
     * Returns the version of the PDP SDK.
118
     *
119
     * @return string
120
     */
121
    public function getVersion()
122
    {
123
        return $this->sdkVersion;
124
    }
125
126
    /**
127
     * Returns the feature level of the SDK.
128
     *
129
     * @return int
130
     */
131
    public function getFeatureLevel()
132
    {
133
        return $this->sdkFeatureLevel;
134
    }
135
136
    /**
137
     * Returns the connector to the Threema Gateway.
138
     *
139
     * @return Threema\MsgApi\Connection
140
     */
141
    public function getConnector()
142
    {
143
        return $this->connector;
144
    }
145
146
    /**
147
     * Returns the E2EHelper to the Threema Gateway.
148
     *
149
     * @throws XenForo_Exception
150
     * @return E2EHelper         The connector to the PHP-SDK
151
     */
152
    public function getE2EHelper()
153
    {
154
        if (!is_object($this->e2eHelper)) {
155
            throw new XenForo_Exception(new XenForo_Phrase('threemagw_missing_e2e_helper'));
156
        }
157
        return $this->e2eHelper;
158
    }
159
160
    /**
161
     * Returns a Receiver for a Threema ID.
162
     *
163
     * @param string $threemaId
164
     *
165
     * @return Receiver
166
     */
167
    public function getReceiver($threemaId)
168
    {
169
        return new Receiver($threemaId, Receiver::TYPE_ID);
170
    }
171
172
    /**
173
     * Returns the crypt tool.
174
     *
175
     * @return Threema\MsgApi\Tools\CryptTool
176
     */
177
    public function getCryptTool()
178
    {
179
        return $this->cryptTool;
180
    }
181
182
    /**
183
     * Returns the settings used for the PHP SDK.
184
     *
185
     * @return ThreemaGateway_Handler_Settings
186
     */
187
    public function getSettings()
188
    {
189
        return $this->settings;
190
    }
191
192
    /**
193
     * Loads the PHP-SDK.
194
     *
195
     * @throws XenForo_Exception
196
     */
197
    protected function loadLib()
198
    {
199
        // use source option can force the use of the source code, but there is
200
        // also an automatic fallback to the source (when the phar does not
201
        // exist)
202
        if (!XenForo_Application::getOptions()->threema_gateway_usesource &&
203
            file_exists($this->sdkDir . '/threema_msgapi.phar')
204
        ) {
205
            // PHAR mode
206
            require_once $this->sdkDir . '/threema_msgapi.phar';
207
        } elseif (file_exists($this->sdkDir . '/source/bootstrap.php')) {
208
            // source mode
209
            $this->sdkDir = $this->sdkDir . '/source';
210
            require_once $this->sdkDir . '/bootstrap.php';
211
        } else {
212
            // error
213
            throw new XenForo_Exception(new XenForo_Phrase('threemagw_missing_sdk'));
214
        }
215
216
        // Set (missing) properties.
217
        $this->sdkVersion      = MSGAPI_SDK_VERSION;
218
        $this->sdkFeatureLevel = MSGAPI_SDK_FEATURE_LEVEL;
219
        $this->cryptTool       = $cryptTool;
220
    }
221
222
    /**
223
     * Creates a keystore.
224
     *
225
     * @param
226
     */
227
    protected function createKeystore()
228
    {
229
        /** @var array $phpKeystore The setting for an optional PHP keystore */
230
        $phpKeystore = XenForo_Application::getOptions()->threema_gateway_keystorefile;
231
232
        if (!$phpKeystore || !$phpKeystore['enabled']) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $phpKeystore of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
233
            $keystore = new ThreemaGateway_Handler_DbKeystore();
234
        } else {
235
            $keystore = new Threema\MsgApi\PublicKeyStores\PhpFile(__DIR__ . '/../' . $phpKeystore['path']);
236
        }
237
        $this->keystore = $keystore;
0 ignored issues
show
Documentation Bug introduced by
It seems like $keystore can also be of type object<Threema\MsgApi\PublicKeyStores\PhpFile>. However, the property $keystore is declared as type object<Threema\MsgApi\PublicKeyStore>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
238
    }
239
240
    /**
241
     * Creates a keystore.
242
     */
243
    protected function createConnection()
244
    {
245
        $connectionSettings = $this->createConnectionSettings(
246
            $this->settings->getId(),
247
            $this->settings->getSecret()
248
        );
249
        $this->connector = new Connection($connectionSettings, $this->keystore);
250
251
        //create E2E helper if E2E mode is used
252
        if ($this->settings->isEndToEnd()) {
253
            $this->e2eHelper = new E2EHelper(
254
                $this->cryptTool->hex2bin(ThreemaGateway_Helper_Key::removeSuffix($this->settings->getPrivateKey())),
255
                $this->connector
256
            );
257
        }
258
    }
259
260
    /**
261
     * Creates connection settings.
262
     *
263
     * @param string $gatewayId     Your own gateway ID
264
     * @param string $gatewaySecret Your own gateway secret
265
     *
266
     * @throws XenForoException
267
     * @return ConnectionSettings
268
     */
269
    protected function createConnectionSettings($gatewayId, $gatewaySecret)
270
    {
271
        /** @var XenForo_Options $xenOptions */
272
        $xenOptions = XenForo_Application::getOptions();
273
274
        /** @var null|ConnectionSettings $settings */
275
        if ($xenOptions->threema_gateway_httpshardening) {
276
            //create a connection with advanced options
277
            switch ($xenOptions->threema_gateway_httpshardening) {
278
                case 1:
279
                    // only force TLS v1.2
280
                    /** @var array $tlsSettings */
281
                    $tlsSettings = [
282
                            'forceHttps' => true,
283
                            'tlsVersion' => '1.2'
284
                        ];
285
                    break;
286
                case 2:
287
                    // also force strong cipher
288
                    /** @var array $tlsSettings */
289
                    $tlsSettings = [
290
                            'forceHttps' => true,
291
                            'tlsVersion' => '1.2',
292
                            'tlsCipher' => 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384'
293
                        ];
294
                    break;
295
                default:
296
                    throw new XenForo_Exception(new XenForo_Phrase('threemagw_invalid_httpshardening_option'));
297
            }
298
299
            return new ConnectionSettings(
300
                $gatewayId,
301
                $gatewaySecret,
302
                null,
303
                $tlsSettings
304
            );
305
        }
306
307
        //create a connection with default options
308
        return new ConnectionSettings(
309
            $gatewayId,
310
            $gatewaySecret
311
        );
312
    }
313
}
314