PluginProbe
UpdraftPlus: WP Backup & Migration Plugin / 1.3.8
UpdraftPlus: WP Backup & Migration Plugin v1.3.8
1.26.7 1.26.6 1.26.5 1.26.4 1.26.3 1.9.19 1.9.25 1.9.26 1.9.30 1.9.31 1.9.32 1.9.4 1.9.40 1.9.41 1.9.42 1.9.43 1.9.44 1.9.45 1.9.46 1.9.5 1.9.50 1.9.51 1.9.60 1.9.62 1.9.63 All 371 releases
updraftplus / includes / Dropbox / OAuth / Consumer / ConsumerAbstract.php

ConsumerAbstract.php in UpdraftPlus: WP Backup & Migration Plugin 1.3.8, at includes/Dropbox/OAuth/Consumer/ConsumerAbstract.php

308 lines 9.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Abstract OAuth consumer
5 * @author Ben Tadiar <ben@handcraftedbyben.co.uk>
6 * @link https://github.com/benthedesigner/dropbox
7 * @package Dropbox\OAuth
8 * @subpackage Consumer
9 */
10
11 abstract class Dropbox_ConsumerAbstract
12 {
13 // Dropbox web endpoint
14 const WEB_URL = 'https://www.dropbox.com/1/';
15
16 // OAuth flow methods
17 const REQUEST_TOKEN_METHOD = 'oauth/request_token';
18 const AUTHORISE_METHOD = 'oauth/authorize';
19 const ACCESS_TOKEN_METHOD = 'oauth/access_token';
20
21 /**
22 * Signature method, either PLAINTEXT or HMAC-SHA1
23 * @var string
24 */
25 private $sigMethod = 'PLAINTEXT';
26
27 /**
28 * Output file handle
29 * @var null|resource
30 */
31 protected $outFile = null;
32
33 /**
34 * Input file handle
35 * @var null|resource
36 */
37 protected $inFile = null;
38
39 /**
40 * Authenticate using 3-legged OAuth flow, firstly
41 * checking we don't already have tokens to use
42 * @return void
43 */
44 protected function authenticate()
45 {
46 if ((!$this->storage->get('access_token'))) {
47 try {
48 $this->getAccessToken();
49 } catch(Dropbox_Exception $e) {
50 $this->getRequestToken();
51 $this->authorise();
52 }
53 }
54 }
55
56 /**
57 * Acquire an unauthorised request token
58 * @link http://tools.ietf.org/html/rfc5849#section-2.1
59 * @return void
60 */
61 private function getRequestToken()
62 {
63 // Nullify any request token we already have
64 $this->storage->set(null, 'request_token');
65 $url = Dropbox_API::API_URL . self::REQUEST_TOKEN_METHOD;
66 $response = $this->fetch('POST', $url, '');
67 $token = $this->parseTokenString($response['body']);
68 $this->storage->set($token, 'request_token');
69 }
70
71 /**
72 * Obtain user authorisation
73 * The user will be redirected to Dropbox' web endpoint
74 * @link http://tools.ietf.org/html/rfc5849#section-2.2
75 * @return void
76 */
77 private function authorise()
78 {
79 // Only redirect if using CLI
80 if (PHP_SAPI !== 'cli') {
81 $url = $this->getAuthoriseUrl();
82 header('Location: ' . $url);
83 exit;
84 }
85 }
86
87 /**
88 * Build the user authorisation URL
89 * @return string
90 */
91 public function getAuthoriseUrl()
92 {
93 // Get the request token
94 $token = $this->getToken();
95
96 // Prepare request parameters
97 $params = array(
98 'oauth_token' => $token->oauth_token,
99 'oauth_token_secret' => $token->oauth_token_secret,
100 'oauth_callback' => $this->callback,
101 );
102
103 // Build the URL and redirect the user
104 $query = '?' . http_build_query($params, '', '&');
105 $url = self::WEB_URL . self::AUTHORISE_METHOD . $query;
106 return $url;
107 }
108
109 /**
110 * Acquire an access token
111 * Tokens acquired at this point should be stored to
112 * prevent having to request new tokens for each API call
113 * @link http://tools.ietf.org/html/rfc5849#section-2.3
114 */
115 public function getAccessToken()
116 {
117 // Get the signed request URL
118 $response = $this->fetch('POST', Dropbox_API::API_URL, self::ACCESS_TOKEN_METHOD);
119 $token = $this->parseTokenString($response['body']);
120 $this->storage->set($token, 'access_token');
121 }
122
123 /**
124 * Get the request/access token
125 * This will return the access/request token depending on
126 * which stage we are at in the OAuth flow, or a dummy object
127 * if we have not yet started the authentication process
128 * @return object stdClass
129 */
130 private function getToken()
131 {
132 if (!$token = $this->storage->get('access_token')) {
133 if (!$token = $this->storage->get('request_token')) {
134 $token = new \stdClass();
135 $token->oauth_token = null;
136 $token->oauth_token_secret = null;
137 }
138 }
139 return $token;
140 }
141
142 /**
143 * Generate signed request URL
144 * See inline comments for description
145 * @link http://tools.ietf.org/html/rfc5849#section-3.4
146 * @param string $method HTTP request method
147 * @param string $url API endpoint to send the request to
148 * @param string $call API call to send
149 * @param array $additional Additional parameters as an associative array
150 * @return array
151 */
152 protected function getSignedRequest($method, $url, $call, array $additional = array())
153 {
154 // Get the request/access token
155 $token = $this->getToken();
156
157 // Generate a random string for the request
158 $nonce = md5(microtime(true) . uniqid('', true));
159
160 // Prepare the standard request parameters
161 $params = array(
162 'oauth_consumer_key' => $this->consumerKey,
163 'oauth_token' => $token->oauth_token,
164 'oauth_signature_method' => $this->sigMethod,
165 'oauth_version' => '1.0',
166 // Generate nonce and timestamp if signature method is HMAC-SHA1
167 'oauth_timestamp' => ($this->sigMethod == 'HMAC-SHA1') ? time() : null,
168 'oauth_nonce' => ($this->sigMethod == 'HMAC-SHA1') ? $nonce : null,
169 );
170
171 // Merge with the additional request parameters
172 $params = array_merge($params, $additional);
173 ksort($params);
174
175 // URL encode each parameter to RFC3986 for use in the base string
176 $encoded = array();
177 foreach($params as $param => $value) {
178 if ($value !== null) {
179 // If the value is a file upload (prefixed with @), replace it with
180 // the destination filename, the file path will be sent in POSTFIELDS
181 if (isset($value[0]) && $value[0] === '@') $value = $params['filename'];
182 $encoded[] = $this->encode($param) . '=' . $this->encode($value);
183 } else {
184 unset($params[$param]);
185 }
186 }
187
188 // Build the first part of the string
189 $base = $method . '&' . $this->encode($url . $call) . '&';
190
191 // Re-encode the encoded parameter string and append to $base
192 $base .= $this->encode(implode('&', $encoded));
193
194 // Concatenate the secrets with an ampersand
195 $key = $this->consumerSecret . '&' . $token->oauth_token_secret;
196
197 // Get the signature string based on signature method
198 $signature = $this->getSignature($base, $key);
199 $params['oauth_signature'] = $signature;
200
201 // Build the signed request URL
202 $query = '?' . http_build_query($params, '', '&');
203
204 return array(
205 'url' => $url . $call . $query,
206 'postfields' => $params,
207 );
208 }
209
210 /**
211 * Generate the oauth_signature for a request
212 * @param string $base Signature base string, used by HMAC-SHA1
213 * @param string $key Concatenated consumer and token secrets
214 */
215 private function getSignature($base, $key)
216 {
217 switch ($this->sigMethod) {
218 case 'PLAINTEXT':
219 $signature = $key;
220 break;
221 case 'HMAC-SHA1':
222 $signature = base64_encode(hash_hmac('sha1', $base, $key, true));
223 break;
224 }
225
226 return $signature;
227 }
228
229 /**
230 * Set the OAuth signature method
231 * @param string $method Either PLAINTEXT or HMAC-SHA1
232 * @return void
233 */
234 public function setSignatureMethod($method)
235 {
236 $method = strtoupper($method);
237
238 switch ($method) {
239 case 'PLAINTEXT':
240 case 'HMAC-SHA1':
241 $this->sigMethod = $method;
242 break;
243 default:
244 throw new Dropbox_Exception('Unsupported signature method ' . $method);
245 }
246 }
247
248 /**
249 * Set the output file
250 * @param resource Resource to stream response data to
251 * @return void
252 */
253 public function setOutFile($handle)
254 {
255 if (!is_resource($handle) || get_resource_type($handle) != 'stream') {
256 throw new Dropbox_Exception('Outfile must be a stream resource');
257 }
258 $this->outFile = $handle;
259 }
260
261 /**
262 * Set the input file
263 * @param resource Resource to read data from
264 * @return void
265 */
266 public function setInFile($handle)
267 {
268 if (!is_resource($handle) || get_resource_type($handle) != 'stream') {
269 throw new Dropbox_Exception('Infile must be a stream resource');
270 }
271 fseek($handle, 0);
272 $this->inFile = $handle;
273 }
274
275 /**
276 * Parse response parameters for a token into an object
277 * Dropbox returns tokens in the response parameters, and
278 * not a JSON encoded object as per other API requests
279 * @link http://oauth.net/core/1.0/#response_parameters
280 * @param string $response
281 * @return object stdClass
282 */
283 private function parseTokenString($response)
284 {
285 $parts = explode('&', $response);
286 $token = new \stdClass();
287 foreach ($parts as $part) {
288 list($k, $v) = explode('=', $part, 2);
289 $k = strtolower($k);
290 $token->$k = $v;
291 }
292 return $token;
293 }
294
295 /**
296 * Encode a value to RFC3986
297 * This is a convenience method to decode ~ symbols encoded
298 * by rawurldecode. This will encode all characters except
299 * the unreserved set, ALPHA, DIGIT, '-', '.', '_', '~'
300 * @link http://tools.ietf.org/html/rfc5849#section-3.6
301 * @param mixed $value
302 */
303 private function encode($value)
304 {
305 return str_replace('%7E', '~', rawurlencode($value));
306 }
307 }
308