rugk/xenforo-threema-gateway

View on GitHub
src/library/ThreemaGateway/Handler/PhpSdk.php

Summary

Maintainability
A
1 hr
Test Coverage
<?php
/**
 * Provides the connection to the PHP SDK.
 *
 * @package ThreemaGateway
 * @author rugk
 * @copyright Copyright (c) 2015-2016 rugk
 * @license MIT
 */

use Threema\MsgApi\Receiver;
use Threema\MsgApi\Helpers\E2EHelper;
use Threema\MsgApi\Connection;
use Threema\MsgApi\ConnectionSettings;

class ThreemaGateway_Handler_PhpSdk
{
    /**
     * @var Singleton
     */
    protected static $instance = null;

    /**
     * @var string Path to Threema Gateway PHP SDK
     */
    protected $sdkDir = __DIR__ . '/../threema-msgapi-sdk-php';

    /**
     * @var ThreemaGateway_Handler_Settings
     */
    protected $settings;

    /**
     * @var string Version of Threema Gateway PHP SDK
     */
    protected $sdkVersion;

    /**
     * @var int Feature level of PHP SDK
     */
    protected $sdkFeatureLevel;

    /**
     * @var Threema\MsgApi\Tools\CryptTool
     */
    protected $cryptTool;

    /**
     * @var Threema\MsgApi\PublicKeyStore
     */
    protected $keystore;

    /**
     * @var Threema\MsgApi\Connection The connector to the PHP-SDK
     */
    protected $connector;

    /**
     * @var E2EHelper The Threema E2E helper, which is necessary when dealing
     *                with end-to-end-encrypted messages.
     */
    protected $e2eHelper;

    /**
     * Initiate PHP-SDK.
     *
     * @param ThreemaGateway_Handler_Settings|null $settings
     * @throws XenForo_Exception
     */
    protected function __construct($settings = null)
    {
        // get options
        if ($settings !== null) {
            $this->settings = $settings;
        } else {
            $this->settings = new ThreemaGateway_Handler_Settings;
        }

        // load libraries
        $this->loadLib();

        //create keystore
        $this->createKeystore();

        //create connection
        $this->createConnection();
    }

    /**
     * Prevent cloning for Singleton.
     */
    protected function __clone()
    {
        // I smash clones!
    }

    /**
     * SDK startup as a Singleton.
     *
     * @param ThreemaGateway_Handler_Settings If you already used the settings
     *                                        you can pass them here, so the
     *                                        class can reuse them.
     * @param  ThreemaGateway_Handler_Settings $settings
     * @throws XenForo_Exception
     * @return void
     */
    public static function getInstance($settings = null)
    {
        if (!isset(self::$instance)) {
            self::$instance = new self($settings);
        }

        return self::$instance;
    }

    /**
     * Returns the version of the PDP SDK.
     *
     * @return string
     */
    public function getVersion()
    {
        return $this->sdkVersion;
    }

    /**
     * Returns the feature level of the SDK.
     *
     * @return int
     */
    public function getFeatureLevel()
    {
        return $this->sdkFeatureLevel;
    }

    /**
     * Returns the connector to the Threema Gateway.
     *
     * @return Threema\MsgApi\Connection
     */
    public function getConnector()
    {
        return $this->connector;
    }

    /**
     * Returns the E2EHelper to the Threema Gateway.
     *
     * @throws XenForo_Exception
     * @return E2EHelper         The connector to the PHP-SDK
     */
    public function getE2EHelper()
    {
        if (!is_object($this->e2eHelper)) {
            throw new XenForo_Exception(new XenForo_Phrase('threemagw_missing_e2e_helper'));
        }
        return $this->e2eHelper;
    }

    /**
     * Returns a Receiver for a Threema ID.
     *
     * @param string $threemaId
     *
     * @return Receiver
     */
    public function getReceiver($threemaId)
    {
        return new Receiver($threemaId, Receiver::TYPE_ID);
    }

    /**
     * Returns the crypt tool.
     *
     * @return Threema\MsgApi\Tools\CryptTool
     */
    public function getCryptTool()
    {
        return $this->cryptTool;
    }

    /**
     * Returns the settings used for the PHP SDK.
     *
     * @return ThreemaGateway_Handler_Settings
     */
    public function getSettings()
    {
        return $this->settings;
    }

    /**
     * Loads the PHP-SDK.
     *
     * @throws XenForo_Exception
     */
    protected function loadLib()
    {
        // use source option can force the use of the source code, but there is
        // also an automatic fallback to the source (when the phar does not
        // exist)
        if (!XenForo_Application::getOptions()->threema_gateway_usesource &&
            file_exists($this->sdkDir . '/threema_msgapi.phar')
        ) {
            // PHAR mode
            require_once $this->sdkDir . '/threema_msgapi.phar';
        } elseif (file_exists($this->sdkDir . '/source/bootstrap.php')) {
            // source mode
            $this->sdkDir = $this->sdkDir . '/source';
            require_once $this->sdkDir . '/bootstrap.php';
        } else {
            // error
            throw new XenForo_Exception(new XenForo_Phrase('threemagw_missing_sdk'));
        }

        // Set (missing) properties.
        $this->sdkVersion      = MSGAPI_SDK_VERSION;
        $this->sdkFeatureLevel = MSGAPI_SDK_FEATURE_LEVEL;
        $this->cryptTool       = $cryptTool;
    }

    /**
     * Creates a keystore.
     *
     * @param
     */
    protected function createKeystore()
    {
        /** @var array $phpKeystore The setting for an optional PHP keystore */
        $phpKeystore = XenForo_Application::getOptions()->threema_gateway_keystorefile;

        if (!$phpKeystore || !$phpKeystore['enabled']) {
            $keystore = new ThreemaGateway_Handler_DbKeystore();
        } else {
            $keystore = new Threema\MsgApi\PublicKeyStores\PhpFile(__DIR__ . '/../' . $phpKeystore['path']);
        }
        $this->keystore = $keystore;
    }

    /**
     * Creates a keystore.
     */
    protected function createConnection()
    {
        $connectionSettings = $this->createConnectionSettings(
            $this->settings->getId(),
            $this->settings->getSecret()
        );
        $this->connector = new Connection($connectionSettings, $this->keystore);

        //create E2E helper if E2E mode is used
        if ($this->settings->isEndToEnd()) {
            $this->e2eHelper = new E2EHelper(
                $this->cryptTool->hex2bin(ThreemaGateway_Helper_Key::removeSuffix($this->settings->getPrivateKey())),
                $this->connector
            );
        }
    }

    /**
     * Creates connection settings.
     *
     * @param string $gatewayId     Your own gateway ID
     * @param string $gatewaySecret Your own gateway secret
     *
     * @throws XenForoException
     * @return ConnectionSettings
     */
    protected function createConnectionSettings($gatewayId, $gatewaySecret)
    {
        /** @var XenForo_Options $xenOptions */
        $xenOptions = XenForo_Application::getOptions();

        /** @var null|ConnectionSettings $settings */
        if ($xenOptions->threema_gateway_httpshardening) {
            //create a connection with advanced options
            switch ($xenOptions->threema_gateway_httpshardening) {
                case 1:
                    // only force TLS v1.2
                    /** @var array $tlsSettings */
                    $tlsSettings = [
                            'forceHttps' => true,
                            'tlsVersion' => '1.2'
                        ];
                    break;
                case 2:
                    // also force strong cipher
                    /** @var array $tlsSettings */
                    $tlsSettings = [
                            'forceHttps' => true,
                            'tlsVersion' => '1.2',
                            'tlsCipher' => 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384'
                        ];
                    break;
                default:
                    throw new XenForo_Exception(new XenForo_Phrase('threemagw_invalid_httpshardening_option'));
            }

            return new ConnectionSettings(
                $gatewayId,
                $gatewaySecret,
                null,
                $tlsSettings
            );
        }

        //create a connection with default options
        return new ConnectionSettings(
            $gatewayId,
            $gatewaySecret
        );
    }
}