Add upstream

This commit is contained in:
root
2019-10-24 00:12:05 +02:00
parent 85d41e4216
commit ac980f592c
3504 changed files with 1049983 additions and 29971 deletions

View File

@@ -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;
}
}

View File

@@ -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();
}

View File

@@ -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);
}
}