plugins/oauth/classes/oauth/yf_oauth_driver1.class.php

Summary

Maintainability
D
2 days
Test Coverage
<?php

load('oauth_driver2', '', 'classes/oauth/');
abstract class yf_oauth_driver1 extends yf_oauth_driver2
{
    protected $url_request_token = '';
    protected $url_access_token = '';
    protected $url_authenticate = '';
    protected $url_user = '';
    protected $scope = '';
    protected $oauth_version = '1.0';
    protected $access_token_use_header = true;
    protected $url_params = [];
    protected $url_params_authorize = [];
    protected $url_params_authenticate = [];
    protected $url_params_request_token = [];
    protected $url_params_access_token = [];
    protected $url_params_user_info = [];
    protected $field_user_id = 'user_id';
    protected $header_add_realm = false;

    // TODO: refresh_token


    public function get_user_info()
    {
        if (DEBUG_MODE && $_GET['oauth_clean']) {
            $this->_storage_clean();
        }
        $access_token = $this->_storage_get('access_token');
        $access_token_secret = $this->_storage_get('access_token_secret');
        if ( ! $access_token || ! $access_token_secret) {
            $result = $this->get_access_token();
            $request_token = $this->_storage_get('request_token');
            if ( ! $access_token && (( ! empty($result) && is_array($result)) || ( ! empty($request_token) && is_array($request_token)))) {
                js_redirect($this->redirect_uri, $url_rewrite = false);
                return false;
            }


            $access_token = $result;

            $access_token_secret = $this->_storage_get('access_token_secret');

            if ( ! $access_token || ! $access_token_secret) {
                common()->message_error('OAuth login error #22. Please contact support');
                js_redirect($this->redirect_uri, $url_rewrite = false);
                return false;
            }
        }
        $oauth_session_handle = $this->_storage_get('oauth_session_handle');
        if ( ! $this->_storage_get('user')) {
            $user_id = $this->_storage_get('user_id');
            $url = $this->url_user;
            $_url_params = $this->url_params + (array) $this->url_params_user_info;
            if ($user_id) {
                if (false !== strpos($url, '{user_id}')) {
                    $url = str_replace('{user_id}', $user_id, $url);
                } else {
                    $_url_params += [
                        'user_id' => $user_id,
                    ];
                }
            }
            if ($_url_params) {
                $url .= (false !== strpos($url, '?') ? '&' : '?') . http_build_query($_url_params);
            }
            $this->_storage_set('nonce', md5(microtime() . rand(1, 10000000)));
            $this->_storage_set('last_time', time());
            $params = (array) $this->url_params + (array) $this->url_params_user_info + [
                    'oauth_version' => $this->oauth_version,
                    'oauth_consumer_key' => $this->client_id,
                    'oauth_nonce' => $this->_storage_get('nonce'),
                    'oauth_timestamp' => $this->_storage_get('last_time'),
                    'oauth_signature_method' => 'HMAC-SHA1',
                    'oauth_token' => $access_token,
                ];
            if ($oauth_session_handle) {
                $params['oauth_session_handle'] = $oauth_session_handle;
            }
            $auth_header = $this->_get_oauth_header($url, $params, 'GET', $access_token_secret);
            $opts = [
                'custom_header' => $auth_header,
            ];
            $result = common()->get_remote_page($url, $cache = false, $opts, $response);
            $result = $this->_decode_result($result, $response, __FUNCTION__);
            if (isset($result['error']) || isset($result['err']) || substr($response['http_code'], 0, 1) == '4') {
                common()->message_error('OAuth login error #33. Please contact support');
                js_redirect($this->redirect_uri, $url_rewrite = false);
                return false;
            }
            $this->_storage_set('user_info_request', ['result' => $result, 'response' => $response]);
            $this->_storage_set('user', $result);
        }
        return $this->_storage_get('user');
    }


    public function get_access_token()
    {
        $access_token = $this->_storage_get('access_token');
        if ($access_token) {
            return $access_token;
        }
        $oauth_verifier = $_GET['oauth_verifier'];
        $oauth_token = $_GET['oauth_token'];
        if (( ! $oauth_verifier || ! $oauth_token) && ! $this->_storage_get('oauth_verifier')) {
            return $this->authenticate();
        }
        $request_token = $this->_storage_get('request_token');
        if ( ! $request_token['oauth_token_secret']) {
            return $this->authenticate();
        }

        $this->_storage_set('nonce', md5(microtime() . rand(1, 10000000)));
        $this->_storage_set('last_time', time());

        $params = (array) $this->url_params + (array) $this->url_params_access_token + [
                'oauth_version' => $this->oauth_version,
                'oauth_consumer_key' => $this->client_id,
                'oauth_nonce' => $this->_storage_get('nonce'),
                'oauth_timestamp' => $this->_storage_get('last_time'),
                'oauth_signature_method' => 'HMAC-SHA1',
                'oauth_token' => $oauth_token,
                'oauth_verifier' => $oauth_verifier,
            ];
        $url = $this->url_access_token;

        $auth_header = $this->_get_oauth_header($url, $params, 'POST', $request_token['oauth_token_secret']);
        if ($this->access_token_use_header) {
            $opts = [
                'post' => [
                    'oauth_verifier' => $oauth_verifier,
                ],
                'custom_header' => $auth_header,
            ];
        } else {
            $opts = [
                'post' => $params,
                'custom_header' => $auth_header,
            ];
        }
        $result = common()->get_remote_page($url, $cache = false, $opts, $response);
        $result = $this->_decode_result($result, ['content_type' => 'application/x-www-form-urlencoded'] + (array) $response, __FUNCTION__);
        if (isset($result['error']) || substr($response['http_code'], 0, 1) == '4') {
            common()->message_error('OAuth login error #44. Please contact support');
            js_redirect($this->redirect_uri, $url_rewrite = false);
            return false;
        }
        $this->_storage_set('access_token_request', ['result' => $result, 'response' => $response]);
        $this->_storage_set('access_token', $result['oauth_token']);
        $this->_storage_set('access_token_secret', $result['oauth_token_secret']);
        $this->_storage_set('oauth_session_handle', $result['oauth_session_handle']);
        $this->_storage_set('user_id', $result[$this->field_user_id]);

        $this->_storage_set('oauth_verifier', $oauth_verifier);
        return $this->_storage_get('access_token');
    }


    public function authenticate()
    {
        $request_token_info = $this->_storage_get('request_token');
        if ($_GET['denied'] == $request_token_info['oauth_token'] || ! $request_token_info || ! isset($request_token_info['oauth_token'])) {
            return $this->authorize();
        }
        $url = $this->url_authenticate . '?' . http_build_query((array) $this->url_params + (array) $this->url_params_authenticate + [
                    'oauth_token' => $request_token_info['oauth_token'],
                ]);
        js_redirect($url, $url_rewrite = false);
        return false;
    }


    public function authorize()
    {
        $request_token_info = $this->_storage_get('request_token');
        if ($request_token_info && $_GET['denied'] != $request_token_info['oauth_token']) {
            return $request_token_info;
        }
        $url = $this->url_request_token;

        $this->_storage_set('nonce', md5(microtime() . rand(1, 10000000)));
        $this->_storage_set('last_time', time());

        $params = (array) $this->url_params + (array) $this->url_params_authorize + [
                'oauth_version' => $this->oauth_version,
                'oauth_callback' => $this->redirect_uri,
                'oauth_consumer_key' => $this->client_id,
                'oauth_nonce' => $this->_storage_get('nonce'),
                'oauth_timestamp' => $this->_storage_get('last_time'),
                'oauth_signature_method' => 'HMAC-SHA1',
            ];
        $opts = [
            'post' => [],
            'custom_header' => $this->_get_oauth_header($url, $params),
        ];
        $result = common()->get_remote_page($url, $cache = false, $opts, $response);
        $result = $this->_decode_result($result, ['content_type' => 'application/x-www-form-urlencoded'] + (array) $response, __FUNCTION__);
        $this->_storage_set('authorize_request', ['result' => $result, 'response' => $response]);
        if ($result && $result['oauth_token'] && $result['oauth_token_secret']) {
            $this->_storage_set('request_token', $result);
            if ($_GET['denied']) {
                return js_redirect('/');
            }
            return $result;
        }
        return false;
    }

    /**
     * @param mixed $url
     * @param mixed $params
     * @param mixed $method
     * @param mixed $oauth_token_secret
     * @param mixed $add_to_sign
     */
    public function _get_oauth_header($url, $params, $method = 'POST', $oauth_token_secret = '', $add_to_sign = [])
    {
        if ( ! is_array($params)) {
            $params = [];
        }
        ksort($params);
        $params_to_sign = (array) $params + (array) $add_to_sign;
        $params['oauth_signature'] = $this->_do_sign_request($url, $params_to_sign, $method, $oauth_token_secret);
        $keyval = [];
        foreach ($params as $k => $v) {
            if ($v === null || ! strlen($v)) {
                unset($params[$k]);
                continue;
            }
            $keyval[$k] = $k . '="' . $v . '"';
        }
        $realm = '';
        if ($this->header_add_realm) {
            $realm_url = $url;
            if (is_string($this->header_add_realm) && strlen($this->header_add_realm) > 5) {
                $realm_url = $this->header_add_realm;
            } else {
                $url_query_string = parse_url($url, PHP_URL_QUERY);
                if ($url_query_string) {
                    $realm_url = substr($realm_url, 0, -strlen('?' . $url_query_string));
                }
            }
            $realm = 'realm="' . $realm_url . '"';
        }
        ksort($keyval);
        return 'Authorization: OAuth ' . $realm . ' ' . implode(', ', $keyval);
    }

    /**
     * @param mixed $url
     * @param mixed $params
     * @param mixed $method
     * @param mixed $oauth_token_secret
     */
    public function _do_sign_request($url, $params, $method = 'POST', $oauth_token_secret = '')
    {
        if ( ! is_array($params)) {
            $params = [];
        }
        $sign_str = [];

        $url_query_string = parse_url($url, PHP_URL_QUERY);
        if ($url_query_string) {
            $qs_array = [];
            parse_str($url_query_string, $qs_array);
            foreach ((array) $qs_array as $k => $v) {
                $params[$k] = $v;
            }
            $url = substr($url, 0, -strlen('?' . $url_query_string));
        }

        ksort($params);
        foreach ((array) $params as $k => $v) {
            $sign_str[$k] = $k . '="' . $this->_encode($v) . '"';
        }
        $sign_str = $method . '&' . $this->_encode($url) . '&' . $this->_encode(http_build_query($params));
        // $oauth_token_secret here is empty, it is ok    http://habrahabr.ru/post/145988/
        $sign = $this->_hmac_sha1($sign_str, $this->client_secret . '&' . $oauth_token_secret);
        $sign = $this->_encode(base64_encode($sign));
        return $sign;
    }

    /**
     * @param mixed $data
     * @param mixed $key
     */
    public function _hmac_sha1($data, $key)
    {
        $pack = 'H40';
        if (strlen($key) > 64) {
            $key = pack($pack, sha1($key));
        }
        if (strlen($key) < 64) {
            $key = str_pad($key, 64, "\0");
        }
        return pack($pack, sha1((str_repeat("\x5c", 64) ^ $key) . pack($pack, sha1((str_repeat("\x36", 64) ^ $key) . $data))));
    }

    /**
     * @param mixed $value
     */
    public function _encode($value)
    {
        $func = __FUNCTION__;
        if (is_array($value)) {
            foreach ($value as $k => $v) {
                $value[$key] = $this->$func($v);
            }
            return $value;
        }
        return str_replace('%7E', '~', str_replace('+', ' ', rawurlencode($value)));
        //        return rawurlencode($value);
    }
}