Completed
Push — 2.0-dev ( 5ac841...8e2c1f )
by Michael
05:16
created

Client::toUrl()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
1
<?php
2
/**
3
 * Part of the Joomla Framework OAuth1 Package
4
 *
5
 * @copyright  Copyright (C) 2005 - 2018 Open Source Matters, Inc. All rights reserved.
6
 * @license    GNU General Public License version 2 or later; see LICENSE
7
 */
8
9
namespace Joomla\OAuth1;
10
11
use Joomla\Application\SessionAwareWebApplicationInterface;
12
use Joomla\Http\Http;
13
use Joomla\Http\HttpFactory;
14
use Joomla\Input\Input;
15
use Joomla\Uri\Uri;
16
17
/**
18
 * Joomla Framework class for interacting with an OAuth 1.0 and 1.0a server.
19
 *
20
 * @since  1.0
21
 */
22
abstract class Client
23
{
24
	/**
25
	 * Options for the Client object.
26
	 *
27
	 * @var    array|\ArrayAccess
28
	 * @since  1.0
29
	 */
30
	protected $options;
31
32
	/**
33
	 * Contains access token key, secret and verifier.
34
	 *
35
	 * @var    array
36
	 * @since  1.0
37
	 */
38
	protected $token = [];
39
40
	/**
41
	 * The HTTP client object to use in sending HTTP requests.
42
	 *
43
	 * @var    Http
44
	 * @since  1.0
45
	 */
46
	protected $client;
47
48
	/**
49
	 * The input object to use in retrieving GET/POST data.
50
	 *
51
	 * @var    Input
52
	 * @since  1.0
53
	 */
54
	protected $input;
55
56
	/**
57
	 * The application object to send HTTP headers for redirects.
58
	 *
59
	 * @var    SessionAwareWebApplicationInterface
60
	 * @since  1.0
61
	 */
62
	protected $application;
63
64
	/**
65
	 * Selects which version of OAuth to use: 1.0 or 1.0a.
66
	 *
67
	 * @var    string
68
	 * @since  1.0
69
	 */
70
	protected $version;
71
72
	/**
73
	 * Constructor.
74
	 *
75
	 * @param   SessionAwareWebApplicationInterface  $application  The application object
76
	 * @param   Http                                 $client       The HTTP client object.
77
	 * @param   Input                                $input        The input object
78
	 * @param   array|\ArrayAccess                   $options      OAuth1 Client options.
79
	 * @param   string                               $version      Specify the OAuth version. By default we are using 1.0a.
80
	 *
81
	 * @since   1.0
82
	 */
83
	public function __construct(
84
		SessionAwareWebApplicationInterface $application,
85
		Http $client = null,
86
		Input $input = null,
87
		$options = [],
88
		$version = '1.0a'
89
	)
90
	{
91
		if (!\is_array($options) && !($options instanceof \ArrayAccess))
92
		{
93
			throw new \InvalidArgumentException(
94
				'The options param must be an array or implement the ArrayAccess interface.'
95
			);
96
		}
97
98
		$this->application = $application;
99
		$this->client      = $client ?: HttpFactory::getHttp($options);
100
		$this->input       = $input ?: $application->getInput();
101
		$this->options     = $options;
102
		$this->version     = $version;
103
	}
104
105
	/**
106
	 * Method to form the oauth flow.
107
	 *
108
	 * @return  array|null  The access token.
109
	 *
110
	 * @since   1.0
111
	 * @throws  \DomainException
112
	 */
113
	public function authenticate()
114
	{
115
		// Already got some credentials stored?
116
		if ($this->token)
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->token 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...
117
		{
118
			$response = $this->verifyCredentials();
119
120
			if ($response)
0 ignored issues
show
Bug Best Practice introduced by
The expression $response 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...
121
			{
122
				return $this->token;
123
			}
124
125
			$this->token = null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array of property $token.

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...
126
		}
127
128
		// Check for callback.
129
		if (strcmp($this->version, '1.0a') === 0)
130
		{
131
			$verifier = $this->input->get('oauth_verifier');
132
		}
133
		else
134
		{
135
			$verifier = $this->input->get('oauth_token');
136
		}
137
138
		if (!empty($verifier))
139
		{
140
			$session = $this->application->getSession();
141
142
			// Get token form session.
143
			$this->token = [
144
				'key'    => $session->get('oauth_token.key'),
145
				'secret' => $session->get('oauth_token.secret'),
146
			];
147
148
			// Verify the returned request token.
149
			if (strcmp($this->token['key'], $this->input->get('oauth_token')) !== 0)
150
			{
151
				throw new \DomainException('Bad session!');
152
			}
153
154
			// Set token verifier for 1.0a.
155
			if (strcmp($this->version, '1.0a') === 0)
156
			{
157
				$this->token['verifier'] = $this->input->get('oauth_verifier');
158
			}
159
160
			// Generate access token.
161
			$this->generateAccessToken();
162
163
			// Return the access token.
164
			return $this->token;
165
		}
166
167
		// Generate a request token.
168
		$this->generateRequestToken();
169
170
		// Authenticate the user and authorise the app.
171
		$this->authorise();
172
	}
173
174
	/**
175
	 * Method used to get a request token.
176
	 *
177
	 * @return  void
178
	 *
179
	 * @since   1.1.2
180
	 * @throws  \DomainException
181
	 */
182
	private function generateRequestToken()
183
	{
184
		$parameters = [];
185
186
		// Set the callback URL.
187
		if ($this->getOption('callback'))
188
		{
189
			$parameters['oauth_callback'] = $this->getOption('callback');
190
		}
191
192
		// Make an OAuth request for the Request Token.
193
		$response = $this->oauthRequest($this->getOption('requestTokenURL'), 'POST', $parameters);
194
195
		parse_str($response->body, $params);
196
197
		if (strcmp($this->version, '1.0a') === 0 && strcmp($params['oauth_callback_confirmed'], 'true') !== 0)
198
		{
199
			throw new \DomainException('Bad request token!');
200
		}
201
202
		// Save the request token.
203
		$this->token = ['key' => $params['oauth_token'], 'secret' => $params['oauth_token_secret']];
204
205
		// Save the request token in session
206
		$session = $this->application->getSession();
207
		$session->set('oauth_token.key', $this->token['key']);
208
		$session->set('oauth_token.secret', $this->token['secret']);
209
	}
210
211
	/**
212
	 * Method used to authorise the application.
213
	 *
214
	 * @return  void
215
	 *
216
	 * @since   1.1.2
217
	 */
218
	private function authorise()
219
	{
220
		$url = $this->getOption('authoriseURL') . '?oauth_token=' . $this->token['key'];
221
222
		if ($this->getOption('scope'))
223
		{
224
			$scope = \is_array($this->getOption('scope')) ? implode(' ', $this->getOption('scope')) : $this->getOption('scope');
225
			$url .= '&scope=' . urlencode($scope);
226
		}
227
228
		if ($this->getOption('sendheaders'))
229
		{
230
			$this->application->redirect($url);
231
		}
232
	}
233
234
	/**
235
	 * Method used to get an access token.
236
	 *
237
	 * @return  void
238
	 *
239
	 * @since   1.1.2
240
	 */
241
	private function generateAccessToken()
242
	{
243
		// Set the parameters.
244
		$parameters = [
245
			'oauth_token' => $this->token['key'],
246
		];
247
248
		if (strcmp($this->version, '1.0a') === 0)
249
		{
250
			$parameters = array_merge($parameters, ['oauth_verifier' => $this->token['verifier']]);
251
		}
252
253
		// Make an OAuth request for the Access Token.
254
		$response = $this->oauthRequest($this->getOption('accessTokenURL'), 'POST', $parameters);
255
256
		parse_str($response->body, $params);
257
258
		// Save the access token.
259
		$this->token = ['key' => $params['oauth_token'], 'secret' => $params['oauth_token_secret']];
260
	}
261
262
	/**
263
	 * Method used to make an OAuth request.
264
	 *
265
	 * @param   string  $url         The request URL.
266
	 * @param   string  $method      The request method.
267
	 * @param   array   $parameters  Array containing request parameters.
268
	 * @param   mixed   $data        The POST request data.
269
	 * @param   array   $headers     An array of name-value pairs to include in the header of the request
270
	 *
271
	 * @return  \Joomla\Http\Response
272
	 *
273
	 * @since   1.0
274
	 * @throws  \DomainException
275
	 */
276
	public function oauthRequest($url, $method, $parameters, $data = [], $headers = [])
277
	{
278
		// Set the parameters.
279
		$defaults = [
280
			'oauth_consumer_key'     => $this->getOption('consumer_key'),
281
			'oauth_signature_method' => 'HMAC-SHA1',
282
			'oauth_version'          => '1.0',
283
			'oauth_nonce'            => $this->generateNonce(),
284
			'oauth_timestamp'        => time(),
285
		];
286
287
		$parameters = array_merge($parameters, $defaults);
288
289
		// Do not encode multipart parameters. Do not include $data in the signature if $data is not array.
290
		if (isset($headers['Content-Type']) && strpos($headers['Content-Type'], 'multipart/form-data') !== false || !\is_array($data))
291
		{
292
			$oauthHeaders = $parameters;
293
		}
294
		else
295
		{
296
			// Use all parameters for the signature.
297
			$oauthHeaders = array_merge($parameters, $data);
298
		}
299
300
		// Sign the request.
301
		$oauthHeaders = $this->signRequest($url, $method, $oauthHeaders);
302
303
		// Get parameters for the Authorisation header.
304
		if (\is_array($data))
305
		{
306
			$oauthHeaders = array_diff_key($oauthHeaders, $data);
307
		}
308
309
		// Send the request.
310
		switch ($method)
311
		{
312 View Code Duplication
			case 'GET':
0 ignored issues
show
Duplication introduced by
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...
313
				$url      = $this->toUrl($url, $data);
314
				$response = $this->client->get($url, ['Authorization' => $this->createHeader($oauthHeaders)]);
315
316
				break;
317
318 View Code Duplication
			case 'POST':
0 ignored issues
show
Duplication introduced by
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...
319
				$headers  = array_merge($headers, ['Authorization' => $this->createHeader($oauthHeaders)]);
320
				$response = $this->client->post($url, $data, $headers);
321
322
				break;
323
324 View Code Duplication
			case 'PUT':
0 ignored issues
show
Duplication introduced by
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...
325
				$headers  = array_merge($headers, ['Authorization' => $this->createHeader($oauthHeaders)]);
326
				$response = $this->client->put($url, $data, $headers);
327
328
				break;
329
330 View Code Duplication
			case 'DELETE':
0 ignored issues
show
Duplication introduced by
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...
331
				$headers  = array_merge($headers, ['Authorization' => $this->createHeader($oauthHeaders)]);
332
				$response = $this->client->delete($url, $headers);
333
334
				break;
335
		}
336
337
		// Validate the response code.
338
		$this->validateResponse($url, $response);
0 ignored issues
show
Bug introduced by
The variable $response does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Documentation introduced by
$response is of type object<Joomla\Http\Response>, but the function expects a object<Joomla\OAuth1\Response>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
339
340
		return $response;
341
	}
342
343
	/**
344
	 * Method to validate a response.
345
	 *
346
	 * @param   string    $url       The request URL.
347
	 * @param   Response  $response  The response to validate.
348
	 *
349
	 * @return  void
350
	 *
351
	 * @since   1.0
352
	 * @throws  \DomainException
353
	 */
354
	abstract public function validateResponse($url, $response);
355
356
	/**
357
	 * Method used to create the header for the POST request.
358
	 *
359
	 * @param   array  $parameters  Array containing request parameters.
360
	 *
361
	 * @return  string  The header.
362
	 *
363
	 * @since   1.1.2
364
	 */
365
	private function createHeader(array $parameters): string
366
	{
367
		$header = 'OAuth ';
368
369
		foreach ($parameters as $key => $value)
370
		{
371
			if (!strcmp($header, 'OAuth '))
372
			{
373
				$header .= $key . '="' . $this->safeEncode($value) . '"';
374
			}
375
			else
376
			{
377
				$header .= ', ' . $key . '="' . $value . '"';
378
			}
379
		}
380
381
		return $header;
382
	}
383
384
	/**
385
	 * Method to create the URL formed string with the parameters.
386
	 *
387
	 * @param   string  $url         The request URL.
388
	 * @param   array   $parameters  Array containing request parameters.
389
	 *
390
	 * @return  string  The formed URL.
391
	 *
392
	 * @since   1.0
393
	 */
394
	public function toUrl($url, $parameters)
395
	{
396
		$uri = new Uri($url);
397
		$uri->setQuery($parameters);
398
399
		return (string) $uri;
400
	}
401
402
	/**
403
	 * Method used to sign requests.
404
	 *
405
	 * @param   string  $url         The URL to sign.
406
	 * @param   string  $method      The request method.
407
	 * @param   array   $parameters  Array containing request parameters.
408
	 *
409
	 * @return  array  The array containing the request parameters, including signature.
410
	 *
411
	 * @since   1.1.2
412
	 */
413
	private function signRequest(string $url, string $method, array $parameters): array
414
	{
415
		// Create the signature base string.
416
		$base = $this->baseString($url, $method, $parameters);
417
418
		$parameters['oauth_signature'] = $this->safeEncode(
419
			base64_encode(
420
				hash_hmac('sha1', $base, $this->prepareSigningKey(), true)
421
			)
422
		);
423
424
		return $parameters;
425
	}
426
427
	/**
428
	 * Prepare the signature base string.
429
	 *
430
	 * @param   string  $url         The URL to sign.
431
	 * @param   string  $method      The request method.
432
	 * @param   array   $parameters  Array containing request parameters.
433
	 *
434
	 * @return  string  The base string.
435
	 *
436
	 * @since   1.1.2
437
	 */
438
	private function baseString(string $url, string $method, array $parameters): string
439
	{
440
		// Sort the parameters alphabetically
441
		uksort($parameters, 'strcmp');
442
443
		// Encode parameters.
444
		foreach ($parameters as $key => $value)
445
		{
446
			$key = $this->safeEncode($key);
447
448
			if (\is_array($value))
449
			{
450
				foreach ($value as $k => $v)
451
				{
452
					$v    = $this->safeEncode($v);
453
					$kv[] = "{$key}={$v}";
0 ignored issues
show
Coding Style Comprehensibility introduced by
$kv was never initialized. Although not strictly required by PHP, it is generally a good practice to add $kv = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
454
				}
455
			}
456
			else
457
			{
458
				$value = $this->safeEncode($value);
459
				$kv[]  = "{$key}={$value}";
0 ignored issues
show
Bug introduced by
The variable $kv does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
460
			}
461
		}
462
463
		// Form the parameter string.
464
		$params = implode('&', $kv);
465
466
		// Signature base string elements.
467
		$base = [
468
			$method,
469
			$url,
470
			$params,
471
		];
472
473
		// Return the base string.
474
		return implode('&', $this->safeEncode($base));
475
	}
476
477
	/**
478
	 * Encodes the string or array passed in a way compatible with OAuth.
479
	 * If an array is passed each array value will will be encoded.
480
	 *
481
	 * @param   mixed  $data  The scalar or array to encode.
482
	 *
483
	 * @return  string  $data encoded in a way compatible with OAuth.
484
	 *
485
	 * @since   1.0
486
	 */
487
	public function safeEncode($data)
488
	{
489
		if (\is_array($data))
490
		{
491
			return array_map([$this, 'safeEncode'], $data);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return array_map(array($... 'safeEncode'), $data); (array) is incompatible with the return type documented by Joomla\OAuth1\Client::safeEncode of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
492
		}
493
494
		if (is_scalar($data))
495
		{
496
			return str_ireplace(
497
				['+', '%7E'],
498
				[' ', '~'],
499
				rawurlencode($data)
500
			);
501
		}
502
503
		return '';
504
	}
505
506
	/**
507
	 * Method used to generate the current nonce.
508
	 *
509
	 * @return  string  The current nonce.
510
	 *
511
	 * @since   1.0
512
	 */
513
	public static function generateNonce()
514
	{
515
		// The md5s look nicer than numbers.
516
		return md5(microtime() . random_bytes(16));
517
	}
518
519
	/**
520
	 * Prepares the OAuth signing key.
521
	 *
522
	 * @return  string  The prepared signing key.
523
	 *
524
	 * @since   1.1.2
525
	 */
526
	private function prepareSigningKey(): string
527
	{
528
		return $this->safeEncode($this->getOption('consumer_secret')) . '&' . $this->safeEncode(($this->token) ? $this->token['secret'] : '');
529
	}
530
531
	/**
532
	 * Returns an HTTP 200 OK response code and a representation of the requesting user if authentication was successful;
533
	 * returns a 401 status code and an error message if not.
534
	 *
535
	 * @return  array  The decoded JSON response
536
	 *
537
	 * @since   1.0
538
	 */
539
	abstract public function verifyCredentials();
540
541
	/**
542
	 * Get an option from the OAuth1 Client instance.
543
	 *
544
	 * @param   string  $key      The name of the option to get
545
	 * @param   mixed   $default  Optional default value if the option does not exist
546
	 *
547
	 * @return  mixed  The option value
548
	 *
549
	 * @since   1.0
550
	 */
551
	public function getOption($key, $default = null)
552
	{
553
		return $this->options[$key] ?? $default;
554
	}
555
556
	/**
557
	 * Set an option for the OAuth1 Client instance.
558
	 *
559
	 * @param   string  $key    The name of the option to set
560
	 * @param   mixed   $value  The option value to set
561
	 *
562
	 * @return  $this
563
	 *
564
	 * @since   1.0
565
	 */
566
	public function setOption($key, $value)
567
	{
568
		$this->options[$key] = $value;
569
570
		return $this;
571
	}
572
573
	/**
574
	 * Get the oauth token key or secret.
575
	 *
576
	 * @return  array  The oauth token key and secret.
577
	 *
578
	 * @since   1.0
579
	 */
580
	public function getToken()
581
	{
582
		return $this->token;
583
	}
584
585
	/**
586
	 * Set the oauth token.
587
	 *
588
	 * @param   array  $token  The access token key and secret.
589
	 *
590
	 * @return  $this
591
	 *
592
	 * @since   1.0
593
	 */
594
	public function setToken($token)
595
	{
596
		$this->token = $token;
597
598
		return $this;
599
	}
600
}
601