Add upstream
This commit is contained in:
		| @@ -0,0 +1,116 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * This class provides the functionality to encrypt | ||||
|  * and decrypt access tokens stored by the application | ||||
|  * @author Ben Tadiar <ben@handcraftedbyben.co.uk> | ||||
|  * @link https://github.com/benthedesigner/dropbox | ||||
|  * @package Dropbox\Oauth | ||||
|  * @subpackage Storage | ||||
|  */ | ||||
|  | ||||
| /* UpdraftPlus notes | ||||
| Using this was fairly pointless (it encrypts storage credentials at rest). But, it's implemented now, so needs supporting. | ||||
| Investigation shows that mcrypt and phpseclib native encryption using different padding schemes. | ||||
| As a result, that which is encrypted by phpseclib native can be decrypted by mcrypt, but not vice-versa. Each can (as you'd expect) decrypt the results of their own encryption. | ||||
| As a consequence, it makes sense to always encrypt with phpseclib native, and prefer decrypting with with mcrypt if it is available and otherwise fall back to phpseclib. | ||||
| We could deliberately re-encrypt all loaded information with phpseclib native, but there seems little need for that yet. There can only be a problem if mcrypt is disabled - which pre-July-2015 meant that Dropbox wouldn't work at all. Now, it will force a re-authorisation. | ||||
| */ | ||||
|  | ||||
| class Dropbox_Encrypter | ||||
| {     | ||||
|     // Encryption settings - default settings yield encryption to AES (256-bit) standard | ||||
|     // @todo Provide PHPDOC for each class constant | ||||
|     const KEY_SIZE = 32; | ||||
|     const IV_SIZE = 16; | ||||
|      | ||||
|     /** | ||||
|      * Encryption key | ||||
|      * @var null|string | ||||
|      */ | ||||
|     private $key = null; | ||||
|      | ||||
|     /** | ||||
|      * Check Mcrypt is loaded and set the encryption key | ||||
|      * @param string $key | ||||
|      * @return void | ||||
|      */ | ||||
|     public function __construct($key) | ||||
|     { | ||||
|         if (preg_match('/^[A-Za-z0-9]+$/', $key) && $length = strlen($key) === self::KEY_SIZE) { | ||||
|             # Short-cut so that the mbstring extension is not required | ||||
|             $this->key = $key; | ||||
|         } elseif (($length = mb_strlen($key, '8bit')) !== self::KEY_SIZE) { | ||||
|             throw new Dropbox_Exception('Expecting a ' .  self::KEY_SIZE . ' byte key, got ' . $length); | ||||
|         } else { | ||||
|             // Set the encryption key | ||||
|             $this->key = $key; | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     /** | ||||
|      * Encrypt the OAuth token | ||||
|      * @param \stdClass $token Serialized token object | ||||
|      * @return string | ||||
|      */ | ||||
|     public function encrypt($token) | ||||
|     { | ||||
|  | ||||
|         // Encryption: we always use phpseclib for this | ||||
|         global $updraftplus; | ||||
|         $ensure_phpseclib = $updraftplus->ensure_phpseclib('Crypt_AES'); | ||||
|          | ||||
|         if (is_wp_error($ensure_phpseclib)) { | ||||
|             $updraftplus->log("Failed to load phpseclib classes (".$ensure_phpseclib->get_error_code()."): ".$ensure_phpseclib->get_error_message()); | ||||
|             $updraftplus->log("Failed to load phpseclib classes (".$ensure_phpseclib->get_error_code()."): ".$ensure_phpseclib->get_error_message(), 'error'); | ||||
|             return false; | ||||
|         } | ||||
|          | ||||
|         $updraftplus->ensure_phpseclib('Crypt_Rijndael'); | ||||
|  | ||||
|         if (!function_exists('crypt_random_string')) require_once(UPDRAFTPLUS_DIR.'/vendor/phpseclib/phpseclib/phpseclib/Crypt/Random.php'); | ||||
|          | ||||
|         $iv = crypt_random_string(self::IV_SIZE); | ||||
|          | ||||
|         // Defaults to CBC mode | ||||
|         $rijndael = new Crypt_Rijndael(); | ||||
|          | ||||
|         $rijndael->setKey($this->key); | ||||
|          | ||||
|         $rijndael->setIV($iv); | ||||
|  | ||||
|         $cipherText = $rijndael->encrypt($token); | ||||
|          | ||||
|         return base64_encode($iv . $cipherText); | ||||
|     } | ||||
|      | ||||
|     /** | ||||
|      * Decrypt the ciphertext | ||||
|      * @param string $cipherText | ||||
|      * @return object \stdClass Unserialized token | ||||
|      */ | ||||
|     public function decrypt($cipherText) | ||||
|     { | ||||
|      | ||||
|         // Decryption: prefer mcrypt, if available (since it can decrypt data encrypted by either mcrypt or phpseclib) | ||||
|  | ||||
|         $cipherText = base64_decode($cipherText); | ||||
|         $iv = substr($cipherText, 0, self::IV_SIZE); | ||||
|         $cipherText = substr($cipherText, self::IV_SIZE); | ||||
|      | ||||
|         if (function_exists('mcrypt_decrypt')) { | ||||
|             // @codingStandardsIgnoreLine | ||||
|             $token = @mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $this->key, $cipherText, MCRYPT_MODE_CBC, $iv); | ||||
|         } else { | ||||
|             global $updraftplus; | ||||
|             $updraftplus->ensure_phpseclib('Crypt_Rijndael'); | ||||
|  | ||||
|             $rijndael = new Crypt_Rijndael(); | ||||
|             $rijndael->setKey($this->key); | ||||
|             $rijndael->setIV($iv); | ||||
|             $token = $rijndael->decrypt($cipherText); | ||||
|         } | ||||
|          | ||||
|         return $token; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,30 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * OAuth storage handler interface | ||||
|  * @author Ben Tadiar <ben@handcraftedbyben.co.uk> | ||||
|  * @link https://github.com/benthedesigner/dropbox | ||||
|  * @package Dropbox\OAuth | ||||
|  * @subpackage Storage | ||||
|  */ | ||||
|  | ||||
| interface Dropbox_StorageInterface | ||||
| { | ||||
|     /** | ||||
|      * Get a token by type | ||||
|      * @param string $type Token type to retrieve | ||||
|      */ | ||||
|     public function get($type); | ||||
|      | ||||
|     /** | ||||
|      * Set a token by type | ||||
|      * @param \stdClass $token Token object to set | ||||
|      * @param string $type Token type | ||||
|      */ | ||||
|     public function set($token, $type); | ||||
|      | ||||
|     /** | ||||
|      * Delete tokens for the current session/user | ||||
|      */ | ||||
|     public function delete(); | ||||
| } | ||||
| @@ -0,0 +1,195 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * OAuth storage handler using WordPress options | ||||
|  * This can only be used if you have a WordPress environment loaded, such that the (get|update|delete)_option functions are available | ||||
|  * See an example usage in http://wordpress.org/extend/plugins/updraftplus | ||||
|  * @author David Anderson <david@updraftplus.com> | ||||
|  * @link https://updraftplus.com | ||||
|  * @package Dropbox\Oauth | ||||
|  * @subpackage Storage | ||||
|  */ | ||||
|  | ||||
| class Dropbox_WordPress implements Dropbox_StorageInterface | ||||
| { | ||||
| 	/** | ||||
| 	 * Option name | ||||
| 	 * @var string | ||||
| 	 */ | ||||
| 	protected $option_name_prefix = 'dropbox_token'; | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Option name (array storage) | ||||
| 	 * @var string | ||||
| 	 */ | ||||
| 	protected $option_array = ''; | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Encyption object | ||||
| 	 * @var Encrypter|null | ||||
| 	 */ | ||||
| 	protected $encrypter = null; | ||||
|  | ||||
| 	/** | ||||
| 	 * Backup module object | ||||
| 	 * @var Backup_module_object|null | ||||
| 	 */ | ||||
| 	protected $backup_module_object = null; | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Check if an instance of the encrypter is passed, set the encryption object | ||||
| 	 * @return void | ||||
| 	 */ | ||||
| 	public function __construct(Dropbox_Encrypter $encrypter = null, $option_name_prefix = 'dropbox_token', $option_array = 'dropbox', $backup_module_object) | ||||
| 	{ | ||||
| 		if ($encrypter instanceof Dropbox_Encrypter) { | ||||
| 			$this->encrypter = $encrypter; | ||||
| 		} | ||||
|  | ||||
| 		if ($backup_module_object instanceof UpdraftPlus_BackupModule) { | ||||
| 			$this->backup_module_object = $backup_module_object; | ||||
| 		} | ||||
|  | ||||
| 		$this->option_name_prefix = $option_name_prefix; | ||||
| 		$this->option_array = $option_array; | ||||
|  | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Get an entry from the Dropbox options in the database | ||||
| 	 * If the encryption object is set then decrypt the token before returning | ||||
| 	 * @param string $type is the key to retrieve | ||||
| 	 * @return array|bool | ||||
| 	 */ | ||||
| 	public function get($type) | ||||
| 	{ | ||||
| 		if ($type != 'request_token' && $type != 'access_token' && $type != 'appkey' && $type != 'CSRF' && $type != 'code') { | ||||
| 			throw new Dropbox_Exception("Expected a type of either 'request_token', 'access_token', 'CSRF' or 'code', got '$type'"); | ||||
| 		} else { | ||||
| 			if (false !== ($opts = $this->backup_module_object->get_options())) { | ||||
| 				if ($type == 'request_token' || $type == 'access_token'){ | ||||
| 					if (!empty($opts[$this->option_name_prefix.$type])) { | ||||
| 						$gettoken = $opts[$this->option_name_prefix.$type]; | ||||
| 						$token = $this->decrypt($gettoken); | ||||
| 						return $token; | ||||
| 					} | ||||
| 				} else { | ||||
| 					if (!empty($opts[$type])) { | ||||
| 						return $opts[$type]; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			return false; | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Set a value in the database by type | ||||
| 	 * If the value is a token and the encryption object is set then encrypt the token before storing | ||||
| 	 * @param \stdClass Token object to set | ||||
| 	 * @param string $type Token type | ||||
| 	 * @return void | ||||
| 	 */ | ||||
| 	public function set($token, $type) | ||||
| 	{ | ||||
| 		if ($type != 'request_token' && $type != 'access_token' && $type != 'upgraded' && $type != 'CSRF' && $type != 'code') { | ||||
| 			throw new Dropbox_Exception("Expected a type of either 'request_token', 'access_token', 'CSRF', 'upgraded' or 'code', got '$type'"); | ||||
| 		} else { | ||||
| 			 | ||||
| 			$opts = $this->backup_module_object->get_options(); | ||||
| 			 | ||||
| 			if ($type == 'access_token'){ | ||||
| 				$token = $this->encrypt($token); | ||||
| 				$opts[$this->option_name_prefix.$type] = $token; | ||||
| 			} else if ($type == 'request_token' ) { | ||||
| 				$opts[$this->option_name_prefix.$type] = $token; | ||||
| 			} else { | ||||
| 				$opts[$type] = $token; | ||||
| 			} | ||||
| 			 | ||||
| 			$this->backup_module_object->set_options($opts, true); | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Remove a value in the database by type rather than setting to null / empty | ||||
| 	 * set the value to null here so that when it gets to the options filter it will | ||||
| 	 * unset the value there, this avoids a bug where if the value is not set then  | ||||
| 	 * the option filter will take the value from the database and save that version back. | ||||
| 	 *  | ||||
| 	 * N.B. Before PHP 7.0, you can't call a method name unset() | ||||
| 	 *  | ||||
| 	 * @param string $type Token type | ||||
| 	 * @return void | ||||
| 	 */ | ||||
| 	public function do_unset($type) | ||||
| 	{ | ||||
| 		if ($type != 'request_token' && $type != 'access_token' && $type != 'upgraded' && $type != 'CSRF' && $type != 'code') { | ||||
| 			throw new Dropbox_Exception("Expected a type of either 'request_token', 'access_token', 'CSRF', 'upgraded' or 'code', got '$type'"); | ||||
| 		} else { | ||||
| 			 | ||||
| 			$opts = $this->backup_module_object->get_options(); | ||||
| 			 | ||||
| 			if ($type == 'access_token' || $type == 'request_token'){ | ||||
| 				$opts[$this->option_name_prefix.$type] = null; | ||||
| 			} else { | ||||
| 				$opts[$type] = null; | ||||
| 			} | ||||
| 			$this->backup_module_object->set_options($opts, true); | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Delete the request and access tokens currently stored in the database | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	public function delete() | ||||
| 	{ | ||||
| 		$opts = $this->backup_module_object->get_options(); | ||||
| 		$opts[$this->option_name_prefix.'request_token'] = null; | ||||
| 		$opts[$this->option_name_prefix.'access_token'] = null; | ||||
| 		unset($opts['ownername']); | ||||
| 		unset($opts['upgraded']); | ||||
| 		$this->backup_module_object->set_options($opts, true); | ||||
| 		return true; | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Use the Encrypter to encrypt a token and return it | ||||
| 	 * If there is not encrypter object, return just the  | ||||
| 	 * serialized token object for storage | ||||
| 	 * @param stdClass $token OAuth token to encrypt | ||||
| 	 * @return stdClass|string | ||||
| 	 */ | ||||
| 	protected function encrypt($token) | ||||
| 	{ | ||||
| 		// Serialize the token object | ||||
| 		$token = serialize($token); | ||||
| 		 | ||||
| 		// Encrypt the token if there is an Encrypter instance | ||||
| 		if ($this->encrypter instanceof Dropbox_Encrypter) { | ||||
| 			$token = $this->encrypter->encrypt($token); | ||||
| 		} | ||||
| 		 | ||||
| 		// Return the token | ||||
| 		return $token; | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Decrypt a token using the Encrypter object and return it | ||||
| 	 * If there is no Encrypter object, assume the token was stored | ||||
| 	 * serialized and return the unserialized token object | ||||
| 	 * @param stdClass $token OAuth token to encrypt | ||||
| 	 * @return stdClass|string | ||||
| 	 */ | ||||
| 	protected function decrypt($token) | ||||
| 	{ | ||||
| 		// Decrypt the token if there is an Encrypter instance | ||||
| 		if ($this->encrypter instanceof Dropbox_Encrypter) { | ||||
| 			$token = $this->encrypter->decrypt($token); | ||||
| 		} | ||||
| 		 | ||||
| 		// Return the unserialized token | ||||
| 		return @unserialize($token); | ||||
| 	} | ||||
| } | ||||
		Reference in New Issue
	
	Block a user