Completed
Push — master ( eca2d0...d28f07 )
by rugk
02:44
created

ThreemaGateway_Handler_PhpSdk::loadLib()   B

Complexity

Conditions 4
Paths 3

Size

Total Lines 23
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 23
rs 8.7972
c 0
b 0
f 0
cc 4
eloc 12
nc 3
nop 0
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
0 ignored issues
show
Coding Style introduced by
Since you have declared the constructor as private, maybe you should also declare the class as final.
Loading history...
17
{
18
    /**
19
     * @var Singleton
20
     */
21
    private 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
    private 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
    private 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
201
        if (!XenForo_Application::getOptions()->threema_gateway_usesource &&
202
            file_exists($this->sdkDir . '/threema_msgapi.phar')
203
        ) {
204
            // PHAR mode
205
            require_once $this->sdkDir . '/threema_msgapi.phar';
206
        } elseif (file_exists($this->sdkDir . '/source/bootstrap.php')) {
207
            // source mode
208
            $this->sdkDir = $this->sdkDir . '/source';
209
            require_once $this->sdkDir . '/bootstrap.php';
210
        } else {
211
            // error
212
            throw new XenForo_Exception(new XenForo_Phrase('threemagw_missing_sdk'));
213
        }
214
215
        // Set (missing) properties.
216
        $this->sdkVersion      = MSGAPI_SDK_VERSION;
217
        $this->sdkFeatureLevel = MSGAPI_SDK_FEATURE_LEVEL;
218
        $this->cryptTool       = $cryptTool;
219
    }
220
221
    /**
222
     * Creates a keystore.
223
     *
224
     * @param
225
     */
226
    protected function createKeystore()
227
    {
228
        /** @var array $phpKeystore The setting for an optional PHP keystore */
229
        $phpKeystore = XenForo_Application::getOptions()->threema_gateway_keystorefile;
230
231
        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...
232
            $keystore = new ThreemaGateway_Handler_DbKeystore();
233
        } else {
234
            $keystore = new Threema\MsgApi\PublicKeyStores\PhpFile(__DIR__ . '/../' . $phpKeystore['path']);
235
        }
236
        $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...
237
    }
238
239
    /**
240
     * Creates a keystore.
241
     */
242
    protected function createConnection()
243
    {
244
        $connectionSettings = $this->createConnectionSettings(
245
            $this->settings->getId(),
246
            $this->settings->getSecret()
247
        );
248
        $this->connector = new Connection($connectionSettings, $this->keystore);
249
250
        //create E2E helper if E2E mode is used
251
        if ($this->settings->isEndToEnd()) {
252
            $this->e2eHelper = new E2EHelper(
253
                $this->cryptTool->hex2bin(ThreemaGateway_Helper_Key::removeSuffix($this->settings->getPrivateKey())),
254
                $this->connector
255
            );
256
        }
257
    }
258
259
    /**
260
     * Creates connection settings.
261
     *
262
     * @param string $gatewayId     Your own gateway ID
263
     * @param string $gatewaySecret Your own gateway secret
264
     *
265
     * @throws XenForoException
266
     * @return ConnectionSettings
267
     */
268
    protected function createConnectionSettings($gatewayId, $gatewaySecret)
269
    {
270
        /** @var XenForo_Options $xenOptions */
271
        $xenOptions = XenForo_Application::getOptions();
272
273
        /** @var null|ConnectionSettings $settings */
274
        if ($xenOptions->threema_gateway_httpshardening) {
275
            //create a connection with advanced options
276
            switch ($xenOptions->threema_gateway_httpshardening) {
277
                case 1:
278
                    // only force TLS v1.2
279
                    /** @var array $tlsSettings */
280
                    $tlsSettings = [
281
                            'forceHttps' => true,
282
                            'tlsVersion' => '1.2'
283
                        ];
284
                    break;
285
                case 2:
286
                    // also force strong cipher
287
                    /** @var array $tlsSettings */
288
                    $tlsSettings = [
289
                            'forceHttps' => true,
290
                            'tlsVersion' => '1.2',
291
                            'tlsCipher' => 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384'
292
                        ];
293
                    break;
294
                default:
295
                    throw new XenForo_Exception(new XenForo_Phrase('threemagw_invalid_httpshardening_option'));
296
            }
297
298
            return new ConnectionSettings(
299
                $gatewayId,
300
                $gatewaySecret,
301
                null,
302
                $tlsSettings
303
            );
304
        }
305
306
        //create a connection with default options
307
        return new ConnectionSettings(
308
            $gatewayId,
309
            $gatewaySecret
310
        );
311
    }
312
}
313