InfiniteWP Client - Version 1.9.6

Version Description

  • Feb 14th 2022 =
  • Feature: Added support for Litespeed Cache.
  • Improvement: Ensure phpseclib Crypt_Blowfish is loaded over PEARs version.
  • Improvement: Enabled support for new Dropbox OAuth Authentication.
  • Fix: Enabled version number for InfiniteWP MU plugin loader.
  • Fix: Undefined array key hook_suffix warning.
  • Fix: Delete SFTP test backup file on the remote server.
  • Fix: PPL addon editor image not uploaded. (issue happening from 1.9.4.9).
  • Fix: Fatal error while backing up a 0kb file using the single call method on site installed on site with php8 server.
Download this release

Release Info

Developer infinitewp
Plugin Icon 128x128 InfiniteWP Client
Version 1.9.6
Comparing to
See all releases

Code changes from version 1.9.4.11 to 1.9.6

addons/post_links/post.class.php CHANGED
@@ -62,11 +62,16 @@ class IWP_MMB_Post extends IWP_MMB_Core
62
 
63
  // create dynamic url RegExp
64
  $dot_match_count = 0;
65
- $iwp_regexp_url = "";
66
 
67
- if(!empty($post_upload_dir)){
 
 
 
 
 
68
  $iwp_base_url = parse_url($post_upload_dir['url']);
69
  $iwp_regexp_url = $iwp_base_url['host'] . $iwp_base_url['path'];
 
70
  $rep = array(
71
  '/',
72
  '+',
@@ -88,7 +93,6 @@ class IWP_MMB_Post extends IWP_MMB_Core
88
  $iwp_mmb_dot_url = '..' . $iwp_base_url['path'];
89
  $iwp_mmb_dot_url = str_replace($rep, $with, $iwp_mmb_dot_url);
90
  $dot_match_count = preg_match_all('/(<a[^>]+href=\"([^"]+)\"[^>]*>)?(<\s*img.[^\/>]*src="([^"]*' . $iwp_mmb_dot_url . '[^\s]+\.(jpg|jpeg|png|gif|bmp))"[^>]*>)/ixu', $post_data['post_content'], $dot_get_urls, PREG_SET_ORDER);
91
- }
92
 
93
 
94
  if ($dot_match_count > 0) {
62
 
63
  // create dynamic url RegExp
64
  $dot_match_count = 0;
 
65
 
66
+ if(empty($post_upload_dir)){
67
+ $iwp_regexp_url = "";
68
+ $iwp_base_url = array();
69
+ $iwp_base_url['host'] = '';
70
+ $iwp_base_url['path'] = '';
71
+ }else{
72
  $iwp_base_url = parse_url($post_upload_dir['url']);
73
  $iwp_regexp_url = $iwp_base_url['host'] . $iwp_base_url['path'];
74
+ }
75
  $rep = array(
76
  '/',
77
  '+',
93
  $iwp_mmb_dot_url = '..' . $iwp_base_url['path'];
94
  $iwp_mmb_dot_url = str_replace($rep, $with, $iwp_mmb_dot_url);
95
  $dot_match_count = preg_match_all('/(<a[^>]+href=\"([^"]+)\"[^>]*>)?(<\s*img.[^\/>]*src="([^"]*' . $iwp_mmb_dot_url . '[^\s]+\.(jpg|jpeg|png|gif|bmp))"[^>]*>)/ixu', $post_data['post_content'], $dot_get_urls, PREG_SET_ORDER);
 
96
 
97
 
98
  if ($dot_match_count > 0) {
addons/wp_optimize/purge-plugins-cache-class.php CHANGED
@@ -79,6 +79,17 @@ class IWP_MMB_PURGE_CACHE extends IWP_MMB_Core
79
  }
80
  }
81
 
 
 
 
 
 
 
 
 
 
 
 
82
  if ($text !==''){
83
  $cleanup_values['message'] = $text;
84
  return $cleanup_values;
@@ -129,6 +140,15 @@ class IWP_MMB_PURGE_CACHE extends IWP_MMB_Core
129
  return false;
130
  }
131
 
 
 
 
 
 
 
 
 
 
132
  /*
133
  * Public function, Will return the Comet cache plugin is loaded or not
134
  */
@@ -279,6 +299,15 @@ class IWP_MMB_PURGE_CACHE extends IWP_MMB_Core
279
  }
280
  }
281
 
 
 
 
 
 
 
 
 
 
282
  }
283
 
284
  if(class_exists('WpFastestCache')){
79
  }
80
  }
81
 
82
+ if (empty($params) || isset($params['litespeed-cache'])) {
83
+ $response = $this->deleteAllLiteSpeedCache();
84
+ if (!empty($response['success'])) {
85
+ $text .= "<span class='wpm_results_db'> Litespeed Cache"." : " . $response['success'] . "</span><br>";
86
+ $cleanup_values['value_array']['litespeed-cache'] = $values['value'];
87
+ }elseif(!empty($response['error'])){
88
+ $text .= "<span class='wpm_results_db'> Litespeed Cache"." : " . $response['error'] . "</span><br>";
89
+ $cleanup_values['value_array']['auto_optimize'] = 'Litespeed Cache';
90
+ }
91
+ }
92
+
93
  if ($text !==''){
94
  $cleanup_values['message'] = $text;
95
  return $cleanup_values;
140
  return false;
141
  }
142
 
143
+ public function checkLiteSpeedCachePlugin() {
144
+ include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
145
+ if ( is_plugin_active( 'litespeed-cache/litespeed-cache.php' ) ) {
146
+ @include_once(WP_PLUGIN_DIR . '/litespeed-cache/litespeed-cache.php');
147
+ return true;
148
+ }
149
+ return false;
150
+ }
151
+
152
  /*
153
  * Public function, Will return the Comet cache plugin is loaded or not
154
  */
299
  }
300
  }
301
 
302
+ public function deleteAllLiteSpeedCache(){
303
+ if ($this->checkLiteSpeedCachePlugin()) {
304
+ do_action('litespeed_purge_all');
305
+ return array('success' => 'Purged all caches successfully');
306
+ }else {
307
+ return array('error'=>"Litespeed cache not activated", 'error_code' => 'litespeed_cache_plugin_is_not_activated');
308
+ }
309
+ }
310
+
311
  }
312
 
313
  if(class_exists('WpFastestCache')){
backup.class.multicall.php CHANGED
@@ -284,6 +284,10 @@ class IWP_MMB_Backup_Multicall extends IWP_MMB_Core
284
  }
285
  upgradeOldDropBoxBackupList($params['account_info']['iwp_dropbox']);
286
  }
 
 
 
 
287
 
288
  if(file_exists(IWP_BACKUP_DIR) && is_dir(IWP_BACKUP_DIR)){
289
  $this->statusLog($historyID, array('stage' => 'verification', 'status' => 'processing', 'statusMsg' => 'Directory Writable'));
@@ -4523,6 +4527,7 @@ function ftp_backup($historyID,$args = '')
4523
 
4524
  function remove_ftp_backup($args)
4525
  {
 
4526
  extract($args);
4527
  //Args: $ftp_username, $ftp_password, $ftp_hostname, $backup_file, $ftp_remote_folder
4528
  //Args: $ftp_username, $ftp_password, $ftp_hostname, $backup_file, $ftp_remote_folder
@@ -4544,6 +4549,7 @@ function ftp_backup($historyID,$args = '')
4544
  'partial' => 1
4545
  );
4546
  }
 
4547
  if (!$sftp->login($ftp_username, $ftp_password)) {
4548
  return array(
4549
  'error' => 'FTP user name and password invalid',
@@ -4598,6 +4604,7 @@ function ftp_backup($historyID,$args = '')
4598
 
4599
  function get_ftp_backup($args, $current_file_num = 0)
4600
  {
 
4601
  extract($args);
4602
  if(isset($use_sftp) && $use_sftp==1) {
4603
  $port = $ftp_port ? $ftp_port : 22; //default port is 22
@@ -4617,6 +4624,7 @@ function ftp_backup($historyID,$args = '')
4617
  'partial' => 1
4618
  );
4619
  }
 
4620
  if (!$sftp->login($ftp_username, $ftp_password)) {
4621
  return array(
4622
  'error' => 'FTP login failed for ' . $ftp_username . ', ' . $ftp_password,
@@ -4773,14 +4781,31 @@ function ftp_backup($historyID,$args = '')
4773
  else
4774
  $dropbox_destination .= '/' . basename($backup_file);
4775
  }else{
4776
- require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/API.php';
4777
- require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/Exception.php';
4778
- require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/OAuth/Consumer/ConsumerAbstract.php';
4779
- require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/OAuth/Consumer/Curl.php';
4780
-
4781
- $oauth = new IWP_Dropbox_OAuth_Consumer_Curl($dropbox_app_key, $dropbox_app_secure_key);
4782
- $oauth->setToken($dropbox_access_token);
4783
- $dropbox = new IWP_Dropbox_API($oauth);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4784
  $oldRoot = 'Apps/InfiniteWP/';
4785
  $dropbox_destination = $oldRoot.ltrim(trim($dropbox_destination), '/');
4786
  $dropbox_destination = rtrim($dropbox_destination, '/');
@@ -4980,14 +5005,30 @@ function ftp_backup($historyID,$args = '')
4980
  if ($dropbox_site_folder == true)
4981
  $dropbox_destination .= '/' . $this->site_name;
4982
  }else{
4983
- require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/API.php';
4984
- require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/Exception.php';
4985
- require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/OAuth/Consumer/ConsumerAbstract.php';
4986
- require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/OAuth/Consumer/Curl.php';
 
4987
 
4988
- $oauth = new IWP_Dropbox_OAuth_Consumer_Curl($dropbox_app_key, $dropbox_app_secure_key);
4989
- $oauth->setToken($dropbox_access_token);
4990
- $dropbox = new IWP_Dropbox_API($oauth);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4991
  $oldRoot = 'Apps/InfiniteWP/';
4992
  $dropbox_destination = $oldRoot.ltrim(trim($dropbox_destination), '/');
4993
  $dropbox_destination = rtrim($dropbox_destination, '/');
284
  }
285
  upgradeOldDropBoxBackupList($params['account_info']['iwp_dropbox']);
286
  }
287
+
288
+ if (!empty($params['account_info']['iwp_dropbox'])) {
289
+ set_iwp_dropbox_auth_setting($params['account_info']['iwp_dropbox']);
290
+ }
291
 
292
  if(file_exists(IWP_BACKUP_DIR) && is_dir(IWP_BACKUP_DIR)){
293
  $this->statusLog($historyID, array('stage' => 'verification', 'status' => 'processing', 'statusMsg' => 'Directory Writable'));
4527
 
4528
  function remove_ftp_backup($args)
4529
  {
4530
+ global $iwp_backup_core;
4531
  extract($args);
4532
  //Args: $ftp_username, $ftp_password, $ftp_hostname, $backup_file, $ftp_remote_folder
4533
  //Args: $ftp_username, $ftp_password, $ftp_hostname, $backup_file, $ftp_remote_folder
4549
  'partial' => 1
4550
  );
4551
  }
4552
+ $iwp_backup_core->ensure_phpseclib('Crypt_Blowfish', 'Crypt/Blowfish');
4553
  if (!$sftp->login($ftp_username, $ftp_password)) {
4554
  return array(
4555
  'error' => 'FTP user name and password invalid',
4604
 
4605
  function get_ftp_backup($args, $current_file_num = 0)
4606
  {
4607
+ global $iwp_backup_core;
4608
  extract($args);
4609
  if(isset($use_sftp) && $use_sftp==1) {
4610
  $port = $ftp_port ? $ftp_port : 22; //default port is 22
4624
  'partial' => 1
4625
  );
4626
  }
4627
+ $iwp_backup_core->ensure_phpseclib('Crypt_Blowfish', 'Crypt/Blowfish');
4628
  if (!$sftp->login($ftp_username, $ftp_password)) {
4629
  return array(
4630
  'error' => 'FTP login failed for ' . $ftp_username . ', ' . $ftp_password,
4781
  else
4782
  $dropbox_destination .= '/' . basename($backup_file);
4783
  }else{
4784
+
4785
+ if(!isset($dropbox_email) && empty($dropbox_email)){
4786
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/API.php';
4787
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/Exception.php';
4788
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/OAuth/Consumer/ConsumerAbstract.php';
4789
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/OAuth/Consumer/Curl.php';
4790
+
4791
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/backup/dropbox.php';
4792
+
4793
+ $oauth = new IWP_Dropbox_OAuth_Consumer_Curl($dropbox_app_key, $dropbox_app_secure_key);
4794
+ $oauth->setToken($dropbox_access_token);
4795
+ $dropbox = new IWP_Dropbox_API($oauth);
4796
+
4797
+ }else{
4798
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/backup/dropbox.php';
4799
+
4800
+ try{
4801
+ $helper = new IWP_MMB_UploadModule_dropbox();
4802
+ $dropbox = $helper->bootstrap();
4803
+ }
4804
+ catch(Exception $e){
4805
+ return $this->statusLog($historyID, array('stage' => 'uploadDropBox', 'status' => 'error', 'statusMsg' => $e->getMessage(), 'statusCode' => 'dropbox_verification_failed_file_may_be_corrupted'));
4806
+ }
4807
+ }
4808
+
4809
  $oldRoot = 'Apps/InfiniteWP/';
4810
  $dropbox_destination = $oldRoot.ltrim(trim($dropbox_destination), '/');
4811
  $dropbox_destination = rtrim($dropbox_destination, '/');
5005
  if ($dropbox_site_folder == true)
5006
  $dropbox_destination .= '/' . $this->site_name;
5007
  }else{
5008
+ if(!isset($dropbox_email) && empty($dropbox_email)){
5009
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/API.php';
5010
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/Exception.php';
5011
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/OAuth/Consumer/ConsumerAbstract.php';
5012
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/OAuth/Consumer/Curl.php';
5013
 
5014
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/backup/dropbox.php';
5015
+
5016
+ $oauth = new IWP_Dropbox_OAuth_Consumer_Curl($dropbox_app_key, $dropbox_app_secure_key);
5017
+ $oauth->setToken($dropbox_access_token);
5018
+ $dropbox = new IWP_Dropbox_API($oauth);
5019
+
5020
+ }else{
5021
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/backup/dropbox.php';
5022
+
5023
+ try{
5024
+ set_iwp_dropbox_auth_setting($args);
5025
+ $helper = new IWP_MMB_UploadModule_dropbox();
5026
+ $dropbox = $helper->bootstrap();
5027
+ }
5028
+ catch(Exception $e){
5029
+
5030
+ }
5031
+ }
5032
  $oldRoot = 'Apps/InfiniteWP/';
5033
  $dropbox_destination = $oldRoot.ltrim(trim($dropbox_destination), '/');
5034
  $dropbox_destination = rtrim($dropbox_destination, '/');
backup.class.singlecall.php CHANGED
@@ -2027,6 +2027,7 @@ function delete_task_now($task_name){
2027
 
2028
  function ftp_backup($args)
2029
  {
 
2030
  extract($args);
2031
  //Args: $ftp_username, $ftp_password, $ftp_hostname, $backup_file, $ftp_remote_folder, $ftp_site_folder
2032
  if(isset($use_sftp) && $use_sftp==1) {
@@ -2047,6 +2048,7 @@ function ftp_backup($args)
2047
  'partial' => 1
2048
  );
2049
  }
 
2050
  if (!$sftp->login($ftp_username, $ftp_password)) {
2051
  return array(
2052
  'error' => 'FTP login failed for ' . $ftp_username . ', ' . $ftp_password,
@@ -2148,6 +2150,7 @@ function ftp_backup($args)
2148
 
2149
  function remove_ftp_backup($args)
2150
  {
 
2151
  extract($args);
2152
  //Args: $ftp_username, $ftp_password, $ftp_hostname, $backup_file, $ftp_remote_folder
2153
  if(isset($use_sftp) && $use_sftp==1) {
@@ -2168,6 +2171,7 @@ function ftp_backup($args)
2168
  'partial' => 1
2169
  );
2170
  }
 
2171
  if (!$sftp->login($ftp_username, $ftp_password)) {
2172
  return array(
2173
  'error' => 'FTP login failed for ' . $ftp_username . ', ' . $ftp_password,
@@ -2239,14 +2243,30 @@ function ftp_backup($args)
2239
  else
2240
  $dropbox_destination .= '/' . basename($backup_file);
2241
  }else{
2242
- require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/API.php';
2243
- require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/Exception.php';
2244
- require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/OAuth/Consumer/ConsumerAbstract.php';
2245
- require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/OAuth/Consumer/Curl.php';
 
2246
 
2247
- $oauth = new IWP_Dropbox_OAuth_Consumer_Curl($dropbox_app_key, $dropbox_app_secure_key);
2248
- $oauth->setToken($dropbox_access_token);
2249
- $dropbox = new IWP_Dropbox_API($oauth);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2250
  $oldRoot = 'Apps/InfiniteWP/';
2251
  $oldVersion = false;
2252
  $dropbox_destination = $oldRoot.ltrim(trim($dropbox_destination), '/');
@@ -2307,14 +2327,30 @@ function ftp_backup($args)
2307
  $dropbox_destination .= '/' . $this->site_name;
2308
  $oldVersion = true;
2309
  }else{
2310
- require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/API.php';
2311
- require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/Exception.php';
2312
- require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/OAuth/Consumer/ConsumerAbstract.php';
2313
- require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/OAuth/Consumer/Curl.php';
 
2314
 
2315
- $oauth = new IWP_Dropbox_OAuth_Consumer_Curl($dropbox_app_key, $dropbox_app_secure_key);
2316
- $oauth->setToken($dropbox_access_token);
2317
- $dropbox = new IWP_Dropbox_API($oauth);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2318
  $oldRoot = 'Apps/InfiniteWP/';
2319
  $dropbox_destination = $oldRoot.ltrim(trim($dropbox_destination), '/');
2320
  $dropbox_destination = rtrim($dropbox_destination, '/');
2027
 
2028
  function ftp_backup($args)
2029
  {
2030
+ global $iwp_backup_core;
2031
  extract($args);
2032
  //Args: $ftp_username, $ftp_password, $ftp_hostname, $backup_file, $ftp_remote_folder, $ftp_site_folder
2033
  if(isset($use_sftp) && $use_sftp==1) {
2048
  'partial' => 1
2049
  );
2050
  }
2051
+ $iwp_backup_core->ensure_phpseclib('Crypt_Blowfish', 'Crypt/Blowfish');
2052
  if (!$sftp->login($ftp_username, $ftp_password)) {
2053
  return array(
2054
  'error' => 'FTP login failed for ' . $ftp_username . ', ' . $ftp_password,
2150
 
2151
  function remove_ftp_backup($args)
2152
  {
2153
+ global $iwp_backup_core;
2154
  extract($args);
2155
  //Args: $ftp_username, $ftp_password, $ftp_hostname, $backup_file, $ftp_remote_folder
2156
  if(isset($use_sftp) && $use_sftp==1) {
2171
  'partial' => 1
2172
  );
2173
  }
2174
+ $iwp_backup_core->ensure_phpseclib('Crypt_Blowfish', 'Crypt/Blowfish');
2175
  if (!$sftp->login($ftp_username, $ftp_password)) {
2176
  return array(
2177
  'error' => 'FTP login failed for ' . $ftp_username . ', ' . $ftp_password,
2243
  else
2244
  $dropbox_destination .= '/' . basename($backup_file);
2245
  }else{
2246
+ if(!isset($dropbox_email) && empty($dropbox_email)){
2247
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/API.php';
2248
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/Exception.php';
2249
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/OAuth/Consumer/ConsumerAbstract.php';
2250
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/OAuth/Consumer/Curl.php';
2251
 
2252
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/backup/dropbox.php';
2253
+
2254
+ $oauth = new IWP_Dropbox_OAuth_Consumer_Curl($dropbox_app_key, $dropbox_app_secure_key);
2255
+ $oauth->setToken($dropbox_access_token);
2256
+ $dropbox = new IWP_Dropbox_API($oauth);
2257
+
2258
+ }else{
2259
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/backup/dropbox.php';
2260
+
2261
+ try{
2262
+ set_iwp_dropbox_auth_setting($args);
2263
+ $helper = new IWP_MMB_UploadModule_dropbox();
2264
+ $dropbox = $helper->bootstrap();
2265
+ }
2266
+ catch(Exception $e){
2267
+
2268
+ }
2269
+ }
2270
  $oldRoot = 'Apps/InfiniteWP/';
2271
  $oldVersion = false;
2272
  $dropbox_destination = $oldRoot.ltrim(trim($dropbox_destination), '/');
2327
  $dropbox_destination .= '/' . $this->site_name;
2328
  $oldVersion = true;
2329
  }else{
2330
+ if(!isset($dropbox_email) && empty($dropbox_email)){
2331
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/API.php';
2332
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/Exception.php';
2333
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/OAuth/Consumer/ConsumerAbstract.php';
2334
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/OAuth/Consumer/Curl.php';
2335
 
2336
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/backup/dropbox.php';
2337
+
2338
+ $oauth = new IWP_Dropbox_OAuth_Consumer_Curl($dropbox_app_key, $dropbox_app_secure_key);
2339
+ $oauth->setToken($dropbox_access_token);
2340
+ $dropbox = new IWP_Dropbox_API($oauth);
2341
+
2342
+ }else{
2343
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/backup/dropbox.php';
2344
+
2345
+ try{
2346
+ set_iwp_dropbox_auth_setting($args);
2347
+ $helper = new IWP_MMB_UploadModule_dropbox();
2348
+ $dropbox = $helper->bootstrap();
2349
+ }
2350
+ catch(Exception $e){
2351
+
2352
+ }
2353
+ }
2354
  $oldRoot = 'Apps/InfiniteWP/';
2355
  $dropbox_destination = $oldRoot.ltrim(trim($dropbox_destination), '/');
2356
  $dropbox_destination = rtrim($dropbox_destination, '/');
backup/backup-repo-test.php CHANGED
@@ -143,6 +143,7 @@ class IWP_BACKUP_REPO_TEST {
143
  }
144
 
145
  public function SFTPTestConnection($args){
 
146
  extract($args);
147
 
148
  $ftp_hostname = $ftp_hostname ? $ftp_hostname : $hostName;
@@ -160,6 +161,8 @@ class IWP_BACKUP_REPO_TEST {
160
  'errorMsg' => 'Failed to connect to host',
161
  );
162
  }
 
 
163
  if (!$sftp->login($ftp_username, $ftp_password)) {
164
  return array('status' => 'error',
165
  'errorMsg' => 'Invalid FTP Username and password login ',
@@ -188,6 +191,8 @@ class IWP_BACKUP_REPO_TEST {
188
  $sftp->chdir($ftp_remote_folder);
189
  $uploadFilePath = IWP_BACKUP_DIR;
190
  $uploadTestFile = $sftp->put(basename($backup_file),$backup_file,NET_SFTP_LOCAL_FILE);
 
 
191
  @unlink($backup_file);
192
  if ($uploadTestFile === false) {
193
  return array('status' => 'error',
@@ -201,25 +206,48 @@ class IWP_BACKUP_REPO_TEST {
201
 
202
  public function backupRepositoryDropbox($args){
203
  extract($args);
204
- if(isset($dropbox_access_token) && !empty($dropbox_access_token)){
205
- require_once $GLOBALS['iwp_mmb_plugin_dir'].'/lib/Dropbox/API.php';
206
- require_once $GLOBALS['iwp_mmb_plugin_dir'].'/lib/Dropbox/Exception.php';
207
- require_once $GLOBALS['iwp_mmb_plugin_dir'].'/lib/Dropbox/OAuth/Consumer/ConsumerAbstract.php';
208
- require_once $GLOBALS['iwp_mmb_plugin_dir'].'/lib/Dropbox/OAuth/Consumer/Curl.php';
209
-
 
 
210
  try{
211
  $oauth = new IWP_Dropbox_OAuth_Consumer_Curl($dropbox_app_key, $dropbox_app_secure_key);
212
  $oauth->setToken($dropbox_access_token);
213
- $dropbox = new IWP_Dropbox_API($oauth);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
  $oldRoot = 'Apps/InfiniteWP';
215
  $dropbox_destination = $oldRoot.$dropbox_destination;
216
  $response = $dropbox->accountInfo();
217
- return array('status' => 'success');
218
  }
219
  catch(Exception $e){
220
  return array('error' => $e->getMessage(), 'error_code' => 'dropbox_test_failed');
221
  }
222
  }
 
223
  return array('error' => 'Consumer Secret not available', 'error_code' => 'consumer_secret_not_available');
224
  }
225
 
143
  }
144
 
145
  public function SFTPTestConnection($args){
146
+ global $iwp_backup_core;
147
  extract($args);
148
 
149
  $ftp_hostname = $ftp_hostname ? $ftp_hostname : $hostName;
161
  'errorMsg' => 'Failed to connect to host',
162
  );
163
  }
164
+ // Ensure phpseclib Crypt_Blowfish is loaded, over PEAR's
165
+ $iwp_backup_core->ensure_phpseclib('Crypt_Blowfish', 'Crypt/Blowfish');
166
  if (!$sftp->login($ftp_username, $ftp_password)) {
167
  return array('status' => 'error',
168
  'errorMsg' => 'Invalid FTP Username and password login ',
191
  $sftp->chdir($ftp_remote_folder);
192
  $uploadFilePath = IWP_BACKUP_DIR;
193
  $uploadTestFile = $sftp->put(basename($backup_file),$backup_file,NET_SFTP_LOCAL_FILE);
194
+ $remote_test_file = rtrim($ftp_remote_folder, '/') . '/' . basename($backup_file);
195
+ $sftp->delete($remote_test_file);
196
  @unlink($backup_file);
197
  if ($uploadTestFile === false) {
198
  return array('status' => 'error',
206
 
207
  public function backupRepositoryDropbox($args){
208
  extract($args);
209
+ $dropbox = null;
210
+ if(!isset($dropbox_email) && empty($dropbox_email) && isset($dropbox_access_token) && !empty($dropbox_access_token)){
211
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/API.php';
212
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/Exception.php';
213
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/OAuth/Consumer/ConsumerAbstract.php';
214
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/OAuth/Consumer/Curl.php';
215
+
216
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/backup/dropbox.php';
217
  try{
218
  $oauth = new IWP_Dropbox_OAuth_Consumer_Curl($dropbox_app_key, $dropbox_app_secure_key);
219
  $oauth->setToken($dropbox_access_token);
220
+ $dropbox = new IWP_Dropbox_API($oauth);
221
+ }
222
+ catch(Exception $e){
223
+ return array('error' => $e->getMessage(), 'error_code' => 'dropbox_test_failed');
224
+ }
225
+
226
+ }elseif( isset($dropbox_email) && !empty($dropbox_email) ){
227
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/backup/dropbox.php';
228
+
229
+ try{
230
+ set_iwp_dropbox_auth_setting($args);
231
+ $helper = new IWP_MMB_UploadModule_dropbox();
232
+ $dropbox = $helper->bootstrap();
233
+ }
234
+ catch(Exception $e){
235
+ return array('error' => $e->getMessage(), 'error_code' => 'dropbox_test_failed');
236
+ }
237
+ }
238
+
239
+ if (!is_null($dropbox)) {
240
+ try{
241
  $oldRoot = 'Apps/InfiniteWP';
242
  $dropbox_destination = $oldRoot.$dropbox_destination;
243
  $response = $dropbox->accountInfo();
244
+ return array('status' => 'success');
245
  }
246
  catch(Exception $e){
247
  return array('error' => $e->getMessage(), 'error_code' => 'dropbox_test_failed');
248
  }
249
  }
250
+
251
  return array('error' => 'Consumer Secret not available', 'error_code' => 'consumer_secret_not_available');
252
  }
253
 
backup/backup.core.class.php CHANGED
@@ -3738,7 +3738,7 @@ CREATE TABLE $wpdb->signups (
3738
 
3739
  }
3740
 
3741
- public function ensure_phpseclib($classes = false, $class_paths = false) {
3742
 
3743
  $this->no_deprecation_warnings_on_php7();
3744
 
@@ -3761,6 +3761,43 @@ CREATE TABLE $wpdb->signups (
3761
  }
3762
  }
3763
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3764
  public function fetch_log($backup_nonce = '', $log_pointer = 0, $output_format = 'html') {
3765
  global $iwp_backup_core;
3766
 
@@ -3996,6 +4033,9 @@ CREATE TABLE $wpdb->signups (
3996
  'CSRF' => '',
3997
  'dropbox_site_folder' => $dropbox_details['dropbox_site_folder']
3998
  );
 
 
 
3999
  IWP_MMB_Backup_Options::update_iwp_backup_option('IWP_dropbox', $opts);
4000
  }elseif (!empty($params['account_info']['iwp_gdrive'])) {
4001
  update_option('IWP_service', 'googledrive');
@@ -4424,16 +4464,33 @@ CREATE TABLE $wpdb->signups (
4424
  }
4425
 
4426
  public function createCloudInstance($type, $args){
 
4427
  if ($type == 'dropbox') {
4428
  extract($args['iwp_dropbox']);
4429
- require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/API.php';
4430
- require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/Exception.php';
4431
- require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/OAuth/Consumer/ConsumerAbstract.php';
4432
- require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/OAuth/Consumer/Curl.php';
 
4433
 
4434
- $oauth = new IWP_Dropbox_OAuth_Consumer_Curl($dropbox_app_key, $dropbox_app_secure_key);
4435
- $oauth->setToken($dropbox_access_token);
4436
- $dropbox = new IWP_Dropbox_API($oauth);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4437
  return $dropbox;
4438
  }elseif ($type == 'ftp') {
4439
  extract($args['iwp_ftp']);
@@ -4451,6 +4508,7 @@ CREATE TABLE $wpdb->signups (
4451
  if(!$sftp) {
4452
  return false;
4453
  }
 
4454
  if (!$sftp->login($ftp_username, $ftp_password)) {
4455
  return false;
4456
  } else {
@@ -4696,6 +4754,13 @@ CREATE TABLE $wpdb->signups (
4696
  }
4697
  }
4698
  }
 
 
 
 
 
 
 
4699
  }
4700
 
4701
  $files_to_delete = array();
@@ -4752,7 +4817,7 @@ CREATE TABLE $wpdb->signups (
4752
 
4753
  foreach ($instance_settings as $instance_id => $options) {
4754
 
4755
- $remote_obj->set_options($options, false, $instance_id);
4756
 
4757
  foreach ($files as $index => $file) {
4758
  if ($remote_deleted == $remote_delete_limit) {
@@ -4987,6 +5052,9 @@ CREATE TABLE $wpdb->signups (
4987
  'CSRF' => '',
4988
  'dropbox_site_folder' => $dropbox_details['dropbox_site_folder']
4989
  );
 
 
 
4990
  IWP_MMB_Backup_Options::update_iwp_backup_option('IWP_dropbox', $opts);
4991
  }elseif (!empty($params['account_info']['iwp_gdrive'])) {
4992
  $google_details = $params['account_info']['iwp_gdrive'];
3738
 
3739
  }
3740
 
3741
+ public function ensure_phpseclib_old($classes = false, $class_paths = false) {
3742
 
3743
  $this->no_deprecation_warnings_on_php7();
3744
 
3761
  }
3762
  }
3763
 
3764
+ public function ensure_phpseclib($classes = array()) {
3765
+
3766
+ $classes = (array) $classes;
3767
+
3768
+ $this->no_deprecation_warnings_on_php7();
3769
+
3770
+ $any_missing = false;
3771
+
3772
+ foreach ($classes as $cl) {
3773
+ if (!class_exists($cl)) $any_missing = true;
3774
+ }
3775
+
3776
+ if (!$any_missing) return true;
3777
+
3778
+ $ret = true;
3779
+
3780
+ // From phpseclib/phpseclib/phpseclib/bootstrap.php - we nullify it there, but log here instead
3781
+ if (extension_loaded('mbstring')) {
3782
+ // 2 - MB_OVERLOAD_STRING
3783
+ // @codingStandardsIgnoreLine
3784
+ if (ini_get('mbstring.func_overload') & 2) {
3785
+ // We go on to try anyway, in case the caller wasn't using an affected part of phpseclib
3786
+ // @codingStandardsIgnoreLine
3787
+ $ret = new WP_Error('mbstring_func_overload', 'Overloading of string functions using mbstring.func_overload is not supported by phpseclib.');
3788
+ }
3789
+ }
3790
+
3791
+ $phpseclib_dir = $GLOBALS['iwp_mmb_plugin_dir'].'/lib/phpseclib/phpseclib/phpseclib';
3792
+ if (false === strpos(get_include_path(), $phpseclib_dir)) set_include_path(get_include_path().PATH_SEPARATOR.$phpseclib_dir);
3793
+ foreach ($classes as $cl) {
3794
+ $path = str_replace('_', '/', $cl);
3795
+ if (!class_exists($cl)) include_once($phpseclib_dir.'/'.$path.'.php');
3796
+ }
3797
+
3798
+ return $ret;
3799
+ }
3800
+
3801
  public function fetch_log($backup_nonce = '', $log_pointer = 0, $output_format = 'html') {
3802
  global $iwp_backup_core;
3803
 
4033
  'CSRF' => '',
4034
  'dropbox_site_folder' => $dropbox_details['dropbox_site_folder']
4035
  );
4036
+ if ( !empty($dropbox_details['dropbox_email']) ) {
4037
+ $opts['email'] = $dropbox_details['dropbox_email'];
4038
+ }
4039
  IWP_MMB_Backup_Options::update_iwp_backup_option('IWP_dropbox', $opts);
4040
  }elseif (!empty($params['account_info']['iwp_gdrive'])) {
4041
  update_option('IWP_service', 'googledrive');
4464
  }
4465
 
4466
  public function createCloudInstance($type, $args){
4467
+ global $iwp_backup_core;
4468
  if ($type == 'dropbox') {
4469
  extract($args['iwp_dropbox']);
4470
+ if(!isset($dropbox_email) && empty($dropbox_email)){
4471
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/API.php';
4472
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/Exception.php';
4473
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/OAuth/Consumer/ConsumerAbstract.php';
4474
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/lib/Dropbox/OAuth/Consumer/Curl.php';
4475
 
4476
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/backup/dropbox.php';
4477
+
4478
+ $oauth = new IWP_Dropbox_OAuth_Consumer_Curl($dropbox_app_key, $dropbox_app_secure_key);
4479
+ $oauth->setToken($dropbox_access_token);
4480
+ $dropbox = new IWP_Dropbox_API($oauth);
4481
+
4482
+ }else{
4483
+ require_once $GLOBALS['iwp_mmb_plugin_dir'] . '/backup/dropbox.php';
4484
+
4485
+ try{
4486
+ set_iwp_dropbox_auth_setting($args['iwp_dropbox']);
4487
+ $helper = new IWP_MMB_UploadModule_dropbox();
4488
+ $dropbox = $helper->bootstrap();
4489
+ }
4490
+ catch(Exception $e){
4491
+ return false;
4492
+ }
4493
+ }
4494
  return $dropbox;
4495
  }elseif ($type == 'ftp') {
4496
  extract($args['iwp_ftp']);
4508
  if(!$sftp) {
4509
  return false;
4510
  }
4511
+ $iwp_backup_core->ensure_phpseclib('Crypt_Blowfish', 'Crypt/Blowfish');
4512
  if (!$sftp->login($ftp_username, $ftp_password)) {
4513
  return false;
4514
  } else {
4754
  }
4755
  }
4756
  }
4757
+
4758
+ if (isset($backups[$timestamp]['service_setting'])) {
4759
+ $service_setting = $backups[$timestamp]['service_setting'];
4760
+ if (isset($service_setting['dropbox_site_folder'])) {
4761
+ set_iwp_dropbox_auth_setting($service_setting);
4762
+ }
4763
+ }
4764
  }
4765
 
4766
  $files_to_delete = array();
4817
 
4818
  foreach ($instance_settings as $instance_id => $options) {
4819
 
4820
+ $remote_obj->set_options($service_setting, false, $instance_id);
4821
 
4822
  foreach ($files as $index => $file) {
4823
  if ($remote_deleted == $remote_delete_limit) {
5052
  'CSRF' => '',
5053
  'dropbox_site_folder' => $dropbox_details['dropbox_site_folder']
5054
  );
5055
+ if ( !empty($dropbox_details['dropbox_email']) ) {
5056
+ $opts['email'] = $dropbox_details['dropbox_email'];
5057
+ }
5058
  IWP_MMB_Backup_Options::update_iwp_backup_option('IWP_dropbox', $opts);
5059
  }elseif (!empty($params['account_info']['iwp_gdrive'])) {
5060
  $google_details = $params['account_info']['iwp_gdrive'];
backup/backup.upload.php CHANGED
@@ -8,6 +8,8 @@ abstract class IWP_MMB_UploadModule {
8
  private $_options;
9
 
10
  private $_instance_id;
 
 
11
 
12
  /**
13
  * Store options (within this class) for this remote storage module. There is also a parameter for saving to the permanent storage (i.e. database).
@@ -22,6 +24,8 @@ abstract class IWP_MMB_UploadModule {
22
  $this->_options = $options;
23
 
24
  if (null !== $instance_id) $this->set_instance_id($instance_id);
 
 
25
 
26
  if ($save) return $this->save_options();
27
 
@@ -38,9 +42,9 @@ abstract class IWP_MMB_UploadModule {
38
  throw new Exception('set_options() can only be called on a storage method which supports multi_options (this module, '.$this->get_id().', does not)');
39
  }
40
 
41
- if (!$this->_instance_id) {
42
- throw new Exception('set_options() requires an instance ID, but was called without setting one (either directly or via set_instance_id())');
43
- }
44
 
45
  global $iwp_backup_core;
46
 
@@ -291,4 +295,23 @@ abstract class IWP_MMB_UploadModule {
291
  if (is_string($legacy_key)) $iwp_backup_core->jobdata_delete($legacy_key);
292
 
293
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
294
  }
8
  private $_options;
9
 
10
  private $_instance_id;
11
+
12
+ private $_storage;
13
 
14
  /**
15
  * Store options (within this class) for this remote storage module. There is also a parameter for saving to the permanent storage (i.e. database).
24
  $this->_options = $options;
25
 
26
  if (null !== $instance_id) $this->set_instance_id($instance_id);
27
+
28
+ if (!empty($this->_storage)) unset($this->_storage);
29
 
30
  if ($save) return $this->save_options();
31
 
42
  throw new Exception('set_options() can only be called on a storage method which supports multi_options (this module, '.$this->get_id().', does not)');
43
  }
44
 
45
+ // if (!$this->_instance_id) {
46
+ // throw new Exception('set_options() requires an instance ID, but was called without setting one (either directly or via set_instance_id())');
47
+ // }
48
 
49
  global $iwp_backup_core;
50
 
295
  if (is_string($legacy_key)) $iwp_backup_core->jobdata_delete($legacy_key);
296
 
297
  }
298
+
299
+
300
+ /**
301
+ * This method will set the stored storage object to that indicated
302
+ *
303
+ * @param Object $storage - the storage client
304
+ */
305
+ public function set_storage($storage) {
306
+ $this->_storage = $storage;
307
+ }
308
+
309
+ /**
310
+ * This method will return the stored storage client
311
+ *
312
+ * @return Object - the stored remote storage client
313
+ */
314
+ public function get_storage() {
315
+ if (!empty($this->_storage)) return $this->_storage;
316
+ }
317
  }
backup/dropbox.php CHANGED
@@ -31,6 +31,7 @@ class IWP_MMB_UploadModule_dropbox extends IWP_MMB_UploadModule {
31
  $iwp_backup_core->jobdata_set('IWP_dbof_'.$this->current_file_hash, $offset);
32
 
33
  $time_now = microtime(true);
 
34
 
35
  $time_since_last_tick = $time_now - $this->upload_tick;
36
  $data_since_last_tick = $offset - $this->uploaded_offset;
@@ -49,7 +50,7 @@ class IWP_MMB_UploadModule_dropbox extends IWP_MMB_UploadModule {
49
  $new_chunk = max(min($upload_secs * $upload_rate * 0.9, 10485760), 1048576);
50
  $new_chunk = $new_chunk - ($new_chunk % 524288);
51
  $chunk_size = (int)$new_chunk;
52
- $this->dropbox_object->setChunkSize($chunk_size);
53
  $iwp_backup_core->jobdata_set('dropbox_chunk_size', $chunk_size);
54
  }
55
  }
@@ -440,7 +441,7 @@ class IWP_MMB_UploadModule_dropbox extends IWP_MMB_UploadModule {
440
 
441
  }
442
 
443
- public function config_print() {
444
 
445
  $opts = $this->get_options();
446
  $ownername = empty($opts['ownername']) ? '' : $opts['ownername'];
@@ -485,14 +486,18 @@ public function config_print() {
485
  $key = empty($opts['secret']) ? '' : $opts['secret'];
486
  $sec = empty($opts['appkey']) ? '' : $opts['appkey'];
487
 
488
- $oauth2_id = base64_decode('aXA3NGR2Zm1sOHFteTA5');
 
 
 
 
489
 
490
 
491
  // Instantiate the Encrypter and storage objects
492
  $encrypter = new Dropbox_Encrypter('ThisOneDoesNotMatterBeyondLength');
493
 
494
  // Instantiate the storage
495
- $storage = new Dropbox_WordPress($encrypter, "tk_", 'IWP_dropbox', $this);
496
 
497
  // WordPress consumer does not yet work
498
  // $OAuth = new Dropbox_ConsumerWordPress($sec, $key, $storage, $callback);
@@ -507,7 +512,7 @@ public function config_print() {
507
  }
508
 
509
  try {
510
- $OAuth = new Dropbox_Curl($sec, $oauth2_id, $key, $storage, null, null, $deauthenticate);
511
  } catch (Exception $e) {
512
  global $iwp_backup_core;
513
  $iwp_backup_core->log("Dropbox Curl error: ".$e->getMessage());
@@ -516,10 +521,16 @@ public function config_print() {
516
  }
517
 
518
  if ($deauthenticate) return true;
 
 
 
 
 
 
 
 
519
 
520
- $OAuth->setToken($opts['tk_access_token']);
521
- $this->dropbox_object = new IWP_MMB_Dropbox_API($OAuth, $root);
522
- return $this->dropbox_object;
523
  }
524
 
525
  }
31
  $iwp_backup_core->jobdata_set('IWP_dbof_'.$this->current_file_hash, $offset);
32
 
33
  $time_now = microtime(true);
34
+ $storage = $this->get_storage();
35
 
36
  $time_since_last_tick = $time_now - $this->upload_tick;
37
  $data_since_last_tick = $offset - $this->uploaded_offset;
50
  $new_chunk = max(min($upload_secs * $upload_rate * 0.9, 10485760), 1048576);
51
  $new_chunk = $new_chunk - ($new_chunk % 524288);
52
  $chunk_size = (int)$new_chunk;
53
+ $storage->setChunkSize($chunk_size);
54
  $iwp_backup_core->jobdata_set('dropbox_chunk_size', $chunk_size);
55
  }
56
  }
441
 
442
  }
443
 
444
+ public function config_print() {
445
 
446
  $opts = $this->get_options();
447
  $ownername = empty($opts['ownername']) ? '' : $opts['ownername'];
486
  $key = empty($opts['secret']) ? '' : $opts['secret'];
487
  $sec = empty($opts['appkey']) ? '' : $opts['appkey'];
488
 
489
+ $oauth2_id = $key;
490
+ $old_auth = false;
491
+ if ( empty($opts['email']) ) {
492
+ $old_auth = true;
493
+ }
494
 
495
 
496
  // Instantiate the Encrypter and storage objects
497
  $encrypter = new Dropbox_Encrypter('ThisOneDoesNotMatterBeyondLength');
498
 
499
  // Instantiate the storage
500
+ $dropbox_storage = new Dropbox_WordPress($encrypter, "tk_", 'IWP_dropbox', $this);
501
 
502
  // WordPress consumer does not yet work
503
  // $OAuth = new Dropbox_ConsumerWordPress($sec, $key, $storage, $callback);
512
  }
513
 
514
  try {
515
+ $OAuth = new Dropbox_Curl($sec, $oauth2_id, $key, $dropbox_storage, null, null, $deauthenticate, null,$old_auth);
516
  } catch (Exception $e) {
517
  global $iwp_backup_core;
518
  $iwp_backup_core->log("Dropbox Curl error: ".$e->getMessage());
521
  }
522
 
523
  if ($deauthenticate) return true;
524
+
525
+ if ( empty($opts['email']) ) {
526
+ $dropbox_storage->set($opts['tk_access_token'], 'access_token');
527
+ }
528
+
529
+ $storage = new IWP_MMB_Dropbox_API($OAuth, $root);
530
+
531
+ $this->set_storage($storage);
532
 
533
+ return $storage;
 
 
534
  }
535
 
536
  }
core.class.php CHANGED
@@ -793,6 +793,7 @@ Plugin Name: InfiniteWP - Client Loader
793
  Plugin URI: https://infinitewp.com/
794
  Description: This plugin will be created automatically when you activate your InfiniteWP Client plugin to improve the performance. And it will be deleted when you deactivate the client plugin.
795
  Author: Revmakx
 
796
  Author URI: https://infinitewp.com/
797
  */
798
 
@@ -843,6 +844,7 @@ EOF;
843
  $error = error_get_last();
844
  throw new Exception(sprintf('Unable to write loader: %s', $error['message']));
845
  }
 
846
  }
847
 
848
  function error_notices()
793
  Plugin URI: https://infinitewp.com/
794
  Description: This plugin will be created automatically when you activate your InfiniteWP Client plugin to improve the performance. And it will be deleted when you deactivate the client plugin.
795
  Author: Revmakx
796
+ Version: 1.0.0
797
  Author URI: https://infinitewp.com/
798
  */
799
 
844
  $error = error_get_last();
845
  throw new Exception(sprintf('Unable to write loader: %s', $error['message']));
846
  }
847
+ update_option('iwp_mu_plugin_version','1.0.0');
848
  }
849
 
850
  function error_notices()
init.php CHANGED
@@ -4,7 +4,7 @@ Plugin Name: InfiniteWP - Client
4
  Plugin URI: http://infinitewp.com/
5
  Description: This is the client plugin of InfiniteWP that communicates with the InfiniteWP Admin panel.
6
  Author: Revmakx
7
- Version: 1.9.4.11
8
  Author URI: http://www.revmakx.com
9
  Network: true
10
  */
@@ -29,7 +29,7 @@ if(basename($_SERVER['SCRIPT_FILENAME']) == "init.php"):
29
  exit;
30
  endif;
31
  if(!defined('IWP_MMB_CLIENT_VERSION'))
32
- define('IWP_MMB_CLIENT_VERSION', '1.9.4.11');
33
 
34
 
35
 
@@ -3280,7 +3280,7 @@ function iwp_plugin_compatibility_fix(){
3280
  $iwp_plugin_fix->fixSidekickPlugin();
3281
  $iwp_plugin_fix->fixSpamShield();
3282
  $iwp_plugin_fix->fixWpSpamShieldBan();
3283
- $iwp_plugin_fix->fixPantheonGlobals();
3284
 
3285
  }
3286
 
@@ -3291,14 +3291,52 @@ function iwp_mu_plugin_loader(){
3291
  $loaderPath = $mustUsePluginDir.'/'.$loaderName;
3292
 
3293
  if (file_exists($loaderPath)) {
3294
- return;
 
 
 
 
 
 
 
 
 
 
 
 
3295
  }
3296
  try {
3297
- $iwp_mmb_core->registerMustUse($loaderName, $iwp_mmb_core->buildLoaderContent('iwp-client/init.php'));
3298
  } catch (Exception $e) {
3299
  iwp_mmb_response(array('error' => 'Unable to write InfiniteWP Client loader:'.$e->getMessage(), 'error_code' => 'iwp_mu_plugin_loader_failed'), false);
3300
  }
3301
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3302
  if(!function_exists('iwp_mmb_is_WPTC')) {
3303
  function iwp_mmb_is_WPTC() {
3304
  include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
4
  Plugin URI: http://infinitewp.com/
5
  Description: This is the client plugin of InfiniteWP that communicates with the InfiniteWP Admin panel.
6
  Author: Revmakx
7
+ Version: 1.9.6
8
  Author URI: http://www.revmakx.com
9
  Network: true
10
  */
29
  exit;
30
  endif;
31
  if(!defined('IWP_MMB_CLIENT_VERSION'))
32
+ define('IWP_MMB_CLIENT_VERSION', '1.9.6');
33
 
34
 
35
 
3280
  $iwp_plugin_fix->fixSidekickPlugin();
3281
  $iwp_plugin_fix->fixSpamShield();
3282
  $iwp_plugin_fix->fixWpSpamShieldBan();
3283
+ $iwp_plugin_fix->fixGlobals();
3284
 
3285
  }
3286
 
3291
  $loaderPath = $mustUsePluginDir.'/'.$loaderName;
3292
 
3293
  if (file_exists($loaderPath)) {
3294
+ $iwp_mu_plugin_version = get_option('iwp_mu_plugin_version');
3295
+ if(empty($iwp_mu_plugin_version)){
3296
+ $iwp_mu_plugin_version = '1.0.0';
3297
+ $data = build_mu_plugin_version($loaderPath,$iwp_mu_plugin_version);
3298
+ if(!$data){
3299
+ iwp_mmb_response(array('error' => 'Unable to read InfiniteWP must use plugin', 'error_code' => 'iwp_mu_plugin_read_failed'), false);
3300
+ return;
3301
+ }
3302
+ }else{
3303
+ return; //Both file and version number exisit
3304
+ }
3305
+ }else{
3306
+ $data = $iwp_mmb_core->buildLoaderContent('iwp-client/init.php');
3307
  }
3308
  try {
3309
+ $iwp_mmb_core->registerMustUse($loaderName,$data);
3310
  } catch (Exception $e) {
3311
  iwp_mmb_response(array('error' => 'Unable to write InfiniteWP Client loader:'.$e->getMessage(), 'error_code' => 'iwp_mu_plugin_loader_failed'), false);
3312
  }
3313
  }
3314
+
3315
+ function build_mu_plugin_version($loaderPath,$iwp_mu_plugin_version){
3316
+ $res = false;
3317
+ $loaderWritten = @file_get_contents($loaderPath);
3318
+ if($loaderWritten){
3319
+ $res = preg_replace('/Author: Revmakx/', "Author: Revmakx ".PHP_EOL."Version :".$iwp_mu_plugin_version." ", $loaderWritten);
3320
+ }
3321
+ return $res;
3322
+ }
3323
+
3324
+ function set_iwp_dropbox_auth_setting($dropbox_details){
3325
+ if ( !empty($dropbox_details['dropbox_email']) ) {
3326
+ $opts = array(
3327
+ 'appkey' => $dropbox_details['dropbox_app_key'],
3328
+ 'secret' => $dropbox_details['dropbox_app_secure_key'],
3329
+ 'tk_access_token' => $dropbox_details['dropbox_access_token'],
3330
+ 'folder' => $dropbox_details['dropbox_destination'],
3331
+ 'ownername' => '',
3332
+ 'email' => $dropbox_details['dropbox_email'],
3333
+ 'CSRF' => '',
3334
+ 'dropbox_site_folder' => $dropbox_details['dropbox_site_folder']
3335
+ );
3336
+ IWP_MMB_Backup_Options::update_iwp_backup_option('IWP_dropbox', $opts);
3337
+ }
3338
+ }
3339
+
3340
  if(!function_exists('iwp_mmb_is_WPTC')) {
3341
  function iwp_mmb_is_WPTC() {
3342
  include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
lib/Dropbox2/API.php CHANGED
@@ -10,9 +10,7 @@
10
  */
11
  class IWP_MMB_Dropbox_API {
12
  // API Endpoints
13
- const API_URL = 'https://api.dropbox.com/1/';
14
  const API_URL_V2 = 'https://api.dropboxapi.com/';
15
- const CONTENT_URL = 'https://api-content.dropbox.com/1/';
16
  const CONTENT_URL_V2 = 'https://content.dropboxapi.com/2/';
17
 
18
  /**
@@ -71,6 +69,15 @@ class IWP_MMB_Dropbox_API {
71
  $this->root = $root;
72
  }
73
  }
 
 
 
 
 
 
 
 
 
74
 
75
  /**
76
  * Retrieves information about the user's account
@@ -85,68 +92,20 @@ class IWP_MMB_Dropbox_API {
85
 
86
  /**
87
  * Retrieves information about the user's quota
 
88
  * @return object stdClass
89
  */
90
- public function quotaInfo() {
91
  $call = '2/users/get_space_usage';
92
- $params = array('api_v2' => true);
 
 
 
 
93
  $response = $this->fetch('POST', self::API_URL_V2, $call, $params);
94
  return $response;
95
  }
96
 
97
- /**
98
- * Not used
99
- * Uploads a physical file from disk
100
- * Dropbox impose a 150MB limit to files uploaded via the API. If the file
101
- * exceeds this limit or does not exist, an Exception will be thrown
102
- * @param string $file Absolute path to the file to be uploaded
103
- * @param string|bool $filename The destination filename of the uploaded file
104
- * @param string $path Path to upload the file to, relative to root
105
- * @param boolean $overwrite Should the file be overwritten? (Default: true)
106
- * @return object stdClass
107
- */
108
- // public function putFile($file, $filename = false, $path = '', $overwrite = true)
109
- // {
110
- // if (file_exists($file)) {
111
- // if (filesize($file) <= 157286400) {
112
- // $call = 'files/' . $this->root . '/' . $this->encodePath($path);
113
- // // If no filename is provided we'll use the original filename
114
- // $filename = (is_string($filename)) ? $filename : basename($file);
115
- // $params = array(
116
- // 'filename' => $filename,
117
- // 'file' => '@' . str_replace('\\', '/', $file) . ';filename=' . $filename,
118
- // 'overwrite' => (int) $overwrite,
119
- // );
120
- // $response = $this->fetch('POST', self::CONTENT_URL, $call, $params);
121
- // return $response;
122
- // }
123
- // throw new Exception('File exceeds 150MB upload limit');
124
- // }
125
-
126
- // // Throw an Exception if the file does not exist
127
- // throw new Exception('Local file ' . $file . ' does not exist');
128
- // }
129
-
130
- /**
131
- * Not used
132
- * Uploads file data from a stream
133
- * Note: This function is experimental and requires further testing
134
- * @todo Add filesize check
135
- * @param resource $stream A readable stream created using fopen()
136
- * @param string $filename The destination filename, including path
137
- * @param boolean $overwrite Should the file be overwritten? (Default: true)
138
- * @return array
139
- */
140
- // public function putStream($stream, $filename, $overwrite = true)
141
- // {
142
- // $this->OAuth->setInFile($stream);
143
- // $path = $this->encodePath($filename);
144
- // $call = 'files_put/' . $this->root . '/' . $path;
145
- // $params = array('overwrite' => (int) $overwrite);
146
- // $response = $this->fetch('PUT', self::CONTENT_URL, $call, $params);
147
- // return $response;
148
- // }
149
-
150
  /**
151
  * Uploads large files to Dropbox in mulitple chunks
152
  * @param string $file Absolute path to the file to be uploaded
@@ -158,6 +117,94 @@ class IWP_MMB_Dropbox_API {
158
  * @param string|array function to call back to upon each chunk
159
  * @return stdClass
160
  */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
  public function chunkedUpload($file, $filename = false, $path = '', $overwrite = true, $offset = 0, $uploadID = null, $callback = null) {
162
 
163
  if (file_exists($file)) {
@@ -174,8 +221,8 @@ class IWP_MMB_Dropbox_API {
174
 
175
  // Read from the file handle until EOF, uploading each chunk
176
  while ($data = fread($handle, $this->chunkSize)) {
177
-
178
- // Set the file, request parameters and send the request
179
  $this->OAuth->setInFile($data);
180
 
181
  if ($firstCommit) {
@@ -256,6 +303,8 @@ class IWP_MMB_Dropbox_API {
256
 
257
  // $params['cursor']['offset'] = $responseCheck[1];
258
  // $response = $this->append_upload($params, $last_call);
 
 
259
  } else {
260
  throw $e;
261
  }
@@ -264,267 +313,102 @@ class IWP_MMB_Dropbox_API {
264
  }
265
 
266
  /**
267
- * Downloads a file
268
- * Returns the base filename, raw file data and mime type returned by Fileinfo
269
- * @param string $file Path to file, relative to root, including path
270
- * @param string $outFile Filename to write the downloaded file to
271
- * @param string $revision The revision of the file to retrieve
272
- * @param boolean $allow_resume - append to the file if it already exists
273
- * @return array
274
  */
275
- public function getFile($file, $outFile = false, $revision = null, $allow_resume = false) {
276
  // Only allow php response format for this call
277
  if ($this->responseFormat !== 'php') {
278
  throw new Exception('This method only supports the `php` response format');
279
  }
280
-
281
- $handle = null;
282
- if ($outFile !== false) {
283
- // Create a file handle if $outFile is specified
284
- if ($allow_resume && file_exists($outFile)) {
285
- if (!$handle = fopen($outFile, 'a')) {
286
- throw new Exception("Unable to open file handle for $outFile");
287
- } else {
288
- $this->OAuth->setOutFile($handle);
289
- $params['headers'] = array('Range: bytes='.filesize($outFile).'-');
290
- }
291
- }
292
- elseif (!$handle = fopen($outFile, 'w')) {
293
- throw new Exception("Unable to open file handle for $outFile");
294
- } else {
295
- $this->OAuth->setOutFile($handle);
296
  }
297
- }
298
-
299
- $file = $this->encodePath($file);
300
- $call = 'files/download';
301
- $params = array('path' => '/' . $file, 'api_v2' => true, 'content_download' => true);
302
- $response = $this->fetch('GET', self::CONTENT_URL_V2, $call, $params);
303
-
304
- // Close the file handle if one was opened
305
- if ($handle) fclose($handle);
306
 
307
- return array(
308
- 'name' => ($outFile) ? $outFile : basename($file),
309
- 'mime' => $this->getMimeType(($outFile) ? $outFile : $response['body'], $outFile),
310
- 'meta' => json_decode($response['headers']['dropbox-api-result']),
311
- 'data' => $response['body'],
312
- );
 
 
 
 
 
313
  }
314
 
315
  /**
316
- * Not used
317
- * Retrieves file and folder metadata
318
- * @param string $path The path to the file/folder, relative to root
319
- * @param string $rev Return metadata for a specific revision (Default: latest rev)
320
- * @param int $limit Maximum number of listings to return
321
- * @param string $hash Metadata hash to compare against
322
- * @param bool $list Return contents field with response
323
- * @param bool $deleted Include files/folders that have been deleted
324
- * @return object stdClass
325
- */
326
- public function metaData($path = null, $rev = null, $limit = 10000, $hash = false, $list = true, $deleted = false) {
327
- $call = '2/files/get_metadata' ;
328
- $params = array(
329
- 'path' => '/' . $this->normalisePath($path),
330
- 'api_v2' => true
331
- );
332
-
333
- return $this->fetch('POST', self::API_URL_V2, $call, $params);
334
- }
335
-
336
- /**
337
- * Not used
338
- * Return "delta entries", intructing you how to update
339
- * your application state to match the server's state
340
- * Important: This method does not make changes to the application state
341
- * @param null|string $cursor Used to keep track of your current state
342
- * @return array Array of delta entries
343
- */
344
- // public function delta($cursor = null)
345
- // {
346
- // $call = 'delta';
347
- // $params = array('cursor' => $cursor);
348
- // $response = $this->fetch('POST', self::API_URL, $call, $params);
349
- // return $response;
350
- // }
351
-
352
- /**
353
- * Not used
354
- * Obtains metadata for the previous revisions of a file
355
- * @param string Path to the file, relative to root
356
- * @param integer Number of revisions to return (1-1000)
357
- * @return array
358
- */
359
- // public function revisions($file, $limit = 10)
360
- // {
361
- // $call = 'revisions/' . $this->root . '/' . $this->encodePath($file);
362
- // $params = array(
363
- // 'rev_limit' => ($limit < 1) ? 1 : (($limit > 1000) ? 1000 : (int) $limit),
364
- // );
365
- // $response = $this->fetch('GET', self::API_URL, $call, $params);
366
- // return $response;
367
- // }
368
-
369
- /**
370
- * Not used
371
- * Restores a file path to a previous revision
372
- * @param string $file Path to the file, relative to root
373
- * @param string $revision The revision of the file to restore
374
- * @return object stdClass
375
- */
376
- // public function restore($file, $revision)
377
- // {
378
- // $call = 'restore/' . $this->root . '/' . $this->encodePath($file);
379
- // $params = array('rev' => $revision);
380
- // $response = $this->fetch('POST', self::API_URL, $call, $params);
381
- // return $response;
382
- // }
383
-
384
- /**
385
- * Returns metadata for all files and folders that match the search query
386
  * @param mixed $query The search string. Must be at least 3 characters long
387
  * @param string [$path=''] The path to the folder you want to search in
388
  * @param integer [$limit=1000] Maximum number of results to return (1-1000)
389
- * @param integer [$start=0] Result number to start from
390
  * @return array
391
  */
392
- public function search($query, $path = '', $limit = 1000, $start = 0) {
393
- $call = '2/files/search';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
394
  $path = $this->encodePath($path);
395
  // APIv2 requires that the path match this regex: String(pattern="(/(.|[\r\n])*)?|(ns:[0-9]+(/.*)?)")
396
  if ($path && '/' != substr($path, 0, 1)) $path = "/$path";
397
  $params = array(
398
- 'path' => $path,
399
  'query' => $query,
400
- 'start' => $start,
401
- 'max_results' => ($limit < 1) ? 1 : (($limit > 1000) ? 1000 : (int) $limit),
 
 
402
  'api_v2' => true,
403
  );
404
  $response = $this->fetch('POST', self::API_URL_V2, $call, $params);
405
  return $response;
406
  }
407
-
408
- /**
409
- * Not used
410
- * Creates and returns a shareable link to files or folders
411
- * The link returned is for a preview page from which the user an choose to
412
- * download the file if they wish. For direct download links, see media().
413
- * @param string $path The path to the file/folder you want a sharable link to
414
- * @return object stdClass
415
- */
416
- // public function shares($path, $shortUrl = true)
417
- // {
418
- // $call = 'shares/' . $this->root . '/' .$this->encodePath($path);
419
- // $params = array('short_url' => ($shortUrl) ? 1 : 0);
420
- // $response = $this->fetch('POST', self::API_URL, $call, $params);
421
- // return $response;
422
- // }
423
-
424
- /**
425
- * Not used
426
- * Returns a link directly to a file
427
- * @param string $path The path to the media file you want a direct link to
428
- * @return object stdClass
429
- */
430
- // public function media($path)
431
- // {
432
- // $call = 'media/' . $this->root . '/' . $this->encodePath($path);
433
- // $response = $this->fetch('POST', self::API_URL, $call);
434
- // return $response;
435
- // }
436
-
437
- /**
438
- * Not used
439
- * Gets a thumbnail for an image
440
- * @param string $file The path to the image you wish to thumbnail
441
- * @param string $format The thumbnail format, either JPEG or PNG
442
- * @param string $size The size of the thumbnail
443
- * @return array
444
- */
445
- // public function thumbnails($file, $format = 'JPEG', $size = 'small')
446
- // {
447
- // // Only allow php response format for this call
448
- // if ($this->responseFormat !== 'php') {
449
- // throw new Exception('This method only supports the `php` response format');
450
- // }
451
-
452
- // $format = strtoupper($format);
453
- // // If $format is not 'PNG', default to 'JPEG'
454
- // if ($format != 'PNG') $format = 'JPEG';
455
-
456
- // $size = strtolower($size);
457
- // $sizes = array('s', 'm', 'l', 'xl', 'small', 'medium', 'large');
458
- // // If $size is not valid, default to 'small'
459
- // if (!in_array($size, $sizes)) $size = 'small';
460
-
461
- // $call = 'thumbnails/' . $this->root . '/' . $this->encodePath($file);
462
- // $params = array('format' => $format, 'size' => $size);
463
- // $response = $this->fetch('GET', self::CONTENT_URL, $call, $params);
464
-
465
- // return array(
466
- // 'name' => basename($file),
467
- // 'mime' => $this->getMimeType($response['body']),
468
- // 'meta' => json_decode($response['headers']['x-dropbox-metadata']),
469
- // 'data' => $response['body'],
470
- // );
471
- // }
472
-
473
- /**
474
- * Not used
475
- * THIS IS NOT AVAILABLE IN V2.
476
- * Creates and returns a copy_ref to a file
477
- * This reference string can be used to copy that file to another user's
478
- * Dropbox by passing it in as the from_copy_ref parameter on /fileops/copy
479
- * @param $path File for which ref should be created, relative to root
480
- * @return array
481
- */
482
- // public function copyRef($path)
483
- // {
484
- // $call = 'copy_ref/' . $this->root . '/' . $this->encodePath($path);
485
- // $response = $this->fetch('GET', self::API_URL, $call);
486
- // return $response;
487
- // }
488
-
489
- /**
490
- * Not used
491
- * Copies a file or folder to a new location
492
- * @param string $from File or folder to be copied, relative to root
493
- * @param string $to Destination path, relative to root
494
- * @param null|string $fromCopyRef Must be used instead of the from_path
495
- * @return object stdClass
496
- */
497
- // public function copy($from, $to, $fromCopyRef = null)
498
- // {
499
- // $call = 'fileops/copy';
500
- // $params = array(
501
- // 'root' => $this->root,
502
- // 'from_path' => $this->normalisePath($from),
503
- // 'to_path' => $this->normalisePath($to),
504
- // );
505
-
506
- // if ($fromCopyRef) {
507
- // $params['from_path'] = null;
508
- // $params['from_copy_ref'] = $fromCopyRef;
509
- // }
510
-
511
- // $response = $this->fetch('POST', self::API_URL, $call, $params);
512
- // return $response;
513
- // }
514
-
515
  /**
516
- * Not used
517
- * Creates a folder
518
- * @param string New folder to create relative to root
519
- * @return object stdClass
 
520
  */
521
- // public function create($path)
522
- // {
523
- // $call = 'fileops/create_folder';
524
- // $params = array('root' => $this->root, 'path' => $this->normalisePath($path));
525
- // $response = $this->fetch('POST', self::API_URL, $call, $params);
526
- // return $response;
527
- // }
 
 
528
 
529
  /**
530
  * Deletes a file or folder
@@ -532,31 +416,12 @@ class IWP_MMB_Dropbox_API {
532
  * @return object stdClass
533
  */
534
  public function delete($path) {
535
- $call = '2/files/delete';
536
  $params = array('path' => '/' . $this->normalisePath($path), 'api_v2' => true);
537
  $response = $this->fetch('POST', self::API_URL_V2, $call, $params);
538
  return $response;
539
  }
540
-
541
- /**
542
- * Not used
543
- * Moves a file or folder to a new location
544
- * @param string $from File or folder to be moved, relative to root
545
- * @param string $to Destination path, relative to root
546
- * @return object stdClass
547
- */
548
- // public function move($from, $to)
549
- // {
550
- // $call = 'fileops/move';
551
- // $params = array(
552
- // 'root' => $this->root,
553
- // 'from_path' => $this->normalisePath($from),
554
- // 'to_path' => $this->normalisePath($to),
555
- // );
556
- // $response = $this->fetch('POST', self::API_URL, $call, $params);
557
- // return $response;
558
- // }
559
-
560
  /**
561
  * Intermediate fetch function
562
  * @param string $method The HTTP method
@@ -618,6 +483,46 @@ class IWP_MMB_Dropbox_API {
618
  public function setCallback($function) {
619
  $this->callback = $function;
620
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
621
 
622
  /**
623
  * Get the mime type of downloaded file
@@ -658,4 +563,119 @@ class IWP_MMB_Dropbox_API {
658
  // in APIv1, encoding was needed because parameters were passed as part of the URL; this is no longer done in our APIv2 SDK; hence, all that we now do here is normalise.
659
  return $this->normalisePath($path);
660
  }
661
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  */
11
  class IWP_MMB_Dropbox_API {
12
  // API Endpoints
 
13
  const API_URL_V2 = 'https://api.dropboxapi.com/';
 
14
  const CONTENT_URL_V2 = 'https://content.dropboxapi.com/2/';
15
 
16
  /**
69
  $this->root = $root;
70
  }
71
  }
72
+
73
+ /**
74
+ * This function will make a request to refresh the access token
75
+ *
76
+ * @return void
77
+ */
78
+ public function refreshAccessToken() {
79
+ $this->OAuth->refreshAccessToken();
80
+ }
81
 
82
  /**
83
  * Retrieves information about the user's account
92
 
93
  /**
94
  * Retrieves information about the user's quota
95
+ * @param array $options - valid keys are 'timeout'
96
  * @return object stdClass
97
  */
98
+ public function quotaInfo($options = array()) {
99
  $call = '2/users/get_space_usage';
100
+ // Cases have been seen (Apr 2019) where a response came back (HTTP/2.0 response header - suspected outgoing web hosting proxy, as everyone else seems to get HTTP/1.0 and I'm not aware that current Curl versions would do HTTP/2.0 without specifically being told to) after 180 seconds; a valid response, but took a long time.
101
+ $params = array(
102
+ 'api_v2' => true,
103
+ 'timeout' => isset($options['timeout']) ? $options['timeout'] : 20
104
+ );
105
  $response = $this->fetch('POST', self::API_URL_V2, $call, $params);
106
  return $response;
107
  }
108
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  /**
110
  * Uploads large files to Dropbox in mulitple chunks
111
  * @param string $file Absolute path to the file to be uploaded
117
  * @param string|array function to call back to upon each chunk
118
  * @return stdClass
119
  */
120
+
121
+ public function chunked_upload($file, $path = '', $overwrite = true, $uploadID = null, $offset = 0, $isCommit = false) {
122
+ $starting_backup_path_time = time();
123
+
124
+ $file = str_replace("\\", "/",$file);
125
+ if (!file_exists($file)) throw new Exception('Local file ' . $file . ' does not exist');
126
+
127
+ if (!($handle = @fopen($file, 'r'))) throw new Exception('Could not open ' . $file . ' for reading');
128
+
129
+ // Seek to the correct position on the file pointer
130
+ fseek($handle, $offset);
131
+ $to_exit = false;
132
+
133
+ //Set firstCommit to true so that the upload session start endpoint is called.
134
+ $firstCommit = (0 == $offset);
135
+
136
+ // Read from the file handle until EOF, uploading each chunk
137
+ if ($data = fread($handle, $this->chunkSize)) {
138
+
139
+ // Set the file, request parameters and send the request
140
+ $this->OAuth->setInFile($data);
141
+
142
+ if ($firstCommit) {
143
+ $params = array(
144
+ 'close' => false,
145
+ 'api_v2' => true,
146
+ 'content_upload' => true
147
+ );
148
+ $response = $this->fetch('POST', self::CONTENT_URL_V2, 'files/upload_session/start', $params);
149
+ $firstCommit = false;
150
+
151
+ } else {
152
+ $params = array(
153
+ 'cursor' => array(
154
+ 'session_id' => $uploadID,
155
+ // If you send it as a string, Dropbox will be unhappy
156
+ 'offset' => (int)$offset
157
+ ),
158
+ 'api_v2' => true,
159
+ 'content_upload' => true
160
+ );
161
+ $response = $this->append_upload($params, false);
162
+ }
163
+
164
+ // On subsequent chunks, use the upload ID returned by the previous request
165
+ if (isset($response['body']->session_id)) {
166
+ $uploadID = $response['body']->session_id;
167
+ }
168
+
169
+ /*
170
+ API v2 no longer returns the offset, we need to manually work this out. So check that there are no errors and update the offset as well as calling the callback method.
171
+ */
172
+ if (!isset($response['body']->error)) {
173
+ $offset = ftell($handle);
174
+ $output['response']= $response;
175
+ if($isCommit ==false){
176
+
177
+ $output['offset']= $offset;
178
+ $output['upload_id']= $uploadID;
179
+ }
180
+ $this->OAuth->setInFile(null);
181
+ }
182
+
183
+ }
184
+ // Complete the chunked upload
185
+ if ($isCommit) {
186
+ $filename = (is_string($filename)) ? $filename : basename($file);
187
+ $params = array(
188
+ 'cursor' => array(
189
+ 'session_id' => $uploadID,
190
+ 'offset' => (int)$offset
191
+ ),
192
+ 'commit' => array(
193
+ 'path' => '/' . $this->encodePath($path .'/'. $filename),
194
+ 'mode' => 'overwrite'
195
+ ),
196
+ 'api_v2' => true,
197
+ 'content_upload' => true
198
+ );
199
+ $response = $this->append_upload($params, true);
200
+ $offset = ftell($handle);
201
+ $output['response']= $response;
202
+ }
203
+
204
+ fclose($handle);
205
+ return $output;
206
+ }
207
+
208
  public function chunkedUpload($file, $filename = false, $path = '', $overwrite = true, $offset = 0, $uploadID = null, $callback = null) {
209
 
210
  if (file_exists($file)) {
221
 
222
  // Read from the file handle until EOF, uploading each chunk
223
  while ($data = fread($handle, $this->chunkSize)) {
224
+
225
+ // Set the file, request parameters and send the request
226
  $this->OAuth->setInFile($data);
227
 
228
  if ($firstCommit) {
303
 
304
  // $params['cursor']['offset'] = $responseCheck[1];
305
  // $response = $this->append_upload($params, $last_call);
306
+ } elseif (isset($responseCheck) && strpos($responseCheck[0], 'closed') !== false) {
307
+ throw new Exception("Upload with upload_id {$params['cursor']['session_id']} already completed");
308
  } else {
309
  throw $e;
310
  }
313
  }
314
 
315
  /**
316
+ * Chunked downloads a file from Dropbox, it will return false if a file handle is not passed and will return true if the call was successful.
317
+ *
318
+ * @param string $file Path - to file, relative to root, including path
319
+ * @param resource $outFile - the local file handle
320
+ * @param array $options - any extra options to be passed e.g headers
321
+ * @return boolean - a boolean to indicate success or failure
 
322
  */
323
+ public function download($file, $outFile = null, $options = array()) {
324
  // Only allow php response format for this call
325
  if ($this->responseFormat !== 'php') {
326
  throw new Exception('This method only supports the `php` response format');
327
  }
328
+
329
+ if ($outFile) {
330
+ $this->OAuth->setOutFile($outFile);
331
+
332
+ $params = array('path' => '/' . $file, 'api_v2' => true, 'content_download' => true);
333
+
334
+ if (isset($options['headers'])) {
335
+ foreach ($options['headers'] as $key => $header) {
336
+ $headers[] = $key . ': ' . $header;
337
+ }
338
+ $params['headers'] = $headers;
 
 
 
 
 
339
  }
 
 
 
 
 
 
 
 
 
340
 
341
+ $file = $this->encodePath($file);
342
+ $call = 'files/download';
343
+
344
+ $response = $this->fetch('GET', self::CONTENT_URL_V2, $call, $params);
345
+
346
+ fclose($outFile);
347
+
348
+ return true;
349
+ } else {
350
+ return false;
351
+ }
352
  }
353
 
354
  /**
355
+ * Calls the relevant method to return metadata for all files and folders that match the search query
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
356
  * @param mixed $query The search string. Must be at least 3 characters long
357
  * @param string [$path=''] The path to the folder you want to search in
358
  * @param integer [$limit=1000] Maximum number of results to return (1-1000)
359
+ * @param integer [$cursor=''] A Dropbox ID to start the search from
360
  * @return array
361
  */
362
+ public function search($query, $path = '', $limit = 1000, $cursor = '') {
363
+ if (empty($cursor)) {
364
+ return $this->start_search($query, $path, $limit);
365
+ } else {
366
+ return $this->continue_search($cursor);
367
+ }
368
+ }
369
+
370
+ /**
371
+ * This method will start a search for all files and folders that match the search query
372
+ *
373
+ * @param mixed $query - the search string, must be at least 3 characters long
374
+ * @param string $path - the path to the folder you want to search in
375
+ * @param integer $limit - maximum number of results to return (1-1000)
376
+ *
377
+ * @return array - an array of search results
378
+ */
379
+ private function start_search($query, $path, $limit) {
380
+ $call = '2/files/search_v2';
381
  $path = $this->encodePath($path);
382
  // APIv2 requires that the path match this regex: String(pattern="(/(.|[\r\n])*)?|(ns:[0-9]+(/.*)?)")
383
  if ($path && '/' != substr($path, 0, 1)) $path = "/$path";
384
  $params = array(
 
385
  'query' => $query,
386
+ 'options' => array(
387
+ 'path' => $path,
388
+ 'max_results' => ($limit < 1) ? 1 : (($limit > 1000) ? 1000 : (int) $limit),
389
+ ),
390
  'api_v2' => true,
391
  );
392
  $response = $this->fetch('POST', self::API_URL_V2, $call, $params);
393
  return $response;
394
  }
395
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
396
  /**
397
+ * This method will continue a previous search for all files and folders that match the previous search query
398
+ *
399
+ * @param string $cursor - a Dropbox ID to continue the search
400
+ *
401
+ * @return array - an array of search results
402
  */
403
+ private function continue_search($cursor) {
404
+ $call = '2/files/search/continue_v2';
405
+ $params = array(
406
+ 'cursor' => $cursor,
407
+ 'api_v2' => true,
408
+ );
409
+ $response = $this->fetch('POST', self::API_URL_V2, $call, $params);
410
+ return $response;
411
+ }
412
 
413
  /**
414
  * Deletes a file or folder
416
  * @return object stdClass
417
  */
418
  public function delete($path) {
419
+ $call = '2/files/delete_v2';
420
  $params = array('path' => '/' . $this->normalisePath($path), 'api_v2' => true);
421
  $response = $this->fetch('POST', self::API_URL_V2, $call, $params);
422
  return $response;
423
  }
424
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
425
  /**
426
  * Intermediate fetch function
427
  * @param string $method The HTTP method
483
  public function setCallback($function) {
484
  $this->callback = $function;
485
  }
486
+
487
+ public function getFile($file, $outFile = false, $revision = null, $allow_resume = false) {
488
+ // Only allow php response format for this call
489
+ if ($this->responseFormat !== 'php') {
490
+ throw new Exception('This method only supports the `php` response format');
491
+ }
492
+
493
+ $handle = null;
494
+ if ($outFile !== false) {
495
+ // Create a file handle if $outFile is specified
496
+ if ($allow_resume && file_exists($outFile)) {
497
+ if (!$handle = fopen($outFile, 'a')) {
498
+ throw new Exception("Unable to open file handle for $outFile");
499
+ } else {
500
+ $this->OAuth->setOutFile($handle);
501
+ $params['headers'] = array('Range: bytes='.filesize($outFile).'-');
502
+ }
503
+ }
504
+ elseif (!$handle = fopen($outFile, 'w')) {
505
+ throw new Exception("Unable to open file handle for $outFile");
506
+ } else {
507
+ $this->OAuth->setOutFile($handle);
508
+ }
509
+ }
510
+
511
+ $file = $this->encodePath($file);
512
+ $call = 'files/download';
513
+ $params = array('path' => '/' . $file, 'api_v2' => true, 'content_download' => true);
514
+ $response = $this->fetch('GET', self::CONTENT_URL_V2, $call, $params);
515
+
516
+ // Close the file handle if one was opened
517
+ if ($handle) fclose($handle);
518
+
519
+ return array(
520
+ 'name' => ($outFile) ? $outFile : basename($file),
521
+ 'mime' => $this->getMimeType(($outFile) ? $outFile : $response['body'], $outFile),
522
+ 'meta' => json_decode($response['headers']['dropbox-api-result']),
523
+ 'data' => $response['body'],
524
+ );
525
+ }
526
 
527
  /**
528
  * Get the mime type of downloaded file
563
  // in APIv1, encoding was needed because parameters were passed as part of the URL; this is no longer done in our APIv2 SDK; hence, all that we now do here is normalise.
564
  return $this->normalisePath($path);
565
  }
566
+
567
+ public function metaData($path = null, $rev = null, $limit = 10000, $hash = false, $list = true, $deleted = false) {
568
+ $call = '2/files/get_metadata' ;
569
+ $params = array(
570
+ 'path' => '/' . $this->normalisePath($path),
571
+ 'api_v2' => true
572
+ );
573
+
574
+ return $this->fetch('POST', self::API_URL_V2, $call, $params);
575
+ }
576
+
577
+ public function putFile($file, $path = '', $overwrite = true) {
578
+ if (!file_exists($file)) {
579
+ // Throw an Exception if the file does not exist
580
+ throw new Exception('Local file ' . $file . ' does not exist');
581
+ }
582
+ $filesize = iwp_mmb_get_file_size($file);
583
+ if ($filesize >= 157286400) {
584
+ $output = $this->chunked_upload_single_call_new($file, $path,$overwrite);
585
+ return $output;
586
+
587
+ }else{
588
+ $handle = @fopen($file, 'r');
589
+ //Set the file content to $this->InFile
590
+ $this->OAuth->setInFile(fread($handle, filesize($file)));
591
+ fclose($handle);
592
+
593
+ $filename = (is_string($filename)) ? $filename : basename($file);
594
+ $path = '/' . $this->encodePath($path .'/'. $filename);
595
+ $params = array(
596
+ 'path' => $path,
597
+ 'mute' => true,
598
+ 'mode' => 'overwrite',
599
+ 'api_v2' => true,
600
+ 'content_upload' => true
601
+ );
602
+ $response = $this->fetch('POST', self::CONTENT_URL_V2, 'files/upload', $params);
603
+ return $response;
604
+ }
605
+
606
+ }
607
+
608
+ public function chunked_upload_single_call_new($file, $path = '',$overwrite=true){
609
+ $file = str_replace("\\", "/",$file);
610
+ if (!is_readable($file) or !is_file($file))
611
+ throw new Exception("Error: File \"$file\" is not readable or doesn't exist.");
612
+ $file_handle=fopen($file,'r');
613
+ $uploadID=null;
614
+ $offset=0;
615
+ $ProgressFunction=null;
616
+ while ($data=fread($file_handle, (1024*1024*30))) { //1024*1024*30 = 30MB
617
+ $firstCommit = (0 == $offset);
618
+ iwp_mmb_auto_print('dropbox_chucked_upload');
619
+ $this->OAuth->setInFile($data);
620
+
621
+ if ($firstCommit) {
622
+ $params = array(
623
+ 'close' => false,
624
+ 'api_v2' => true,
625
+ 'content_upload' => true
626
+ );
627
+ $response = $this->fetch('POST', self::CONTENT_URL_V2, 'files/upload_session/start', $params);
628
+ $firstCommit = false;
629
+
630
+ } else {
631
+ $params = array(
632
+ 'cursor' => array(
633
+ 'session_id' => $uploadID,
634
+ // If you send it as a string, Dropbox will be unhappy
635
+ 'offset' => (int)$offset
636
+ ),
637
+ 'api_v2' => true,
638
+ 'content_upload' => true
639
+ );
640
+ $response = $this->append_upload($params, false);
641
+ }
642
+
643
+ // On subsequent chunks, use the upload ID returned by the previous request
644
+ if (isset($response['body']->session_id)) {
645
+ $uploadID = $response['body']->session_id;
646
+ }
647
+
648
+ /*
649
+ API v2 no longer returns the offset, we need to manually work this out. So check that there are no errors and update the offset as well as calling the callback method.
650
+ */
651
+ if (!isset($response['body']->error)) {
652
+ $offset = ftell($file_handle);
653
+ $output['response']= $response;
654
+ if($isCommit ==false){
655
+
656
+ $output['offset']= $offset;
657
+ $output['upload_id']= $uploadID;
658
+ }
659
+ $this->OAuth->setInFile(null);
660
+ }
661
+ fseek($file_handle, $offset);
662
+ }
663
+ fclose($file_handle);
664
+ $filename = (is_string($filename)) ? $filename : basename($file);
665
+ $params = array(
666
+ 'cursor' => array(
667
+ 'session_id' => $uploadID,
668
+ 'offset' => (int)$offset
669
+ ),
670
+ 'commit' => array(
671
+ 'path' => '/' . $this->encodePath($path .'/'. $filename),
672
+ 'mode' => 'overwrite'
673
+ ),
674
+ 'api_v2' => true,
675
+ 'content_upload' => true
676
+ );
677
+ $response = $this->append_upload($params, true);
678
+
679
+ return $response;
680
+ }
681
+ }
lib/Dropbox2/OAuth/Consumer/ConsumerAbstract.php CHANGED
@@ -20,14 +20,19 @@ abstract class Dropbox_ConsumerAbstract
20
  const ACCESS_TOKEN_METHOD = 'oauth2/token';
21
  // The next endpoint only exists with APIv1
22
  const OAUTH_UPGRADE = 'oauth2/token_from_oauth1';
 
 
 
 
 
 
 
23
 
24
  /**
25
  * Signature method, either PLAINTEXT or HMAC-SHA1
26
  * @var string
27
  */
28
  private $sigMethod = 'PLAINTEXT';
29
-
30
- private $token = null;
31
 
32
  /**
33
  * Output file handle
@@ -57,6 +62,10 @@ abstract class Dropbox_ConsumerAbstract
57
  $this->upgradeOAuth();
58
  $iwp_backup_core->log('OAuth token upgrade successful');
59
  }
 
 
 
 
60
 
61
  if (empty($access_token) || !isset($access_token->oauth_token)) {
62
  try {
@@ -83,7 +92,7 @@ abstract class Dropbox_ConsumerAbstract
83
  private function upgradeOAuth()
84
  {
85
  // N.B. This call only exists under API v1 - i.e. there is no APIv2 equivalent. Hence the APIv1 endpoint (API_URL) is used, and not the v2 (API_URL_V2)
86
- $url = IWP_MMB_Dropbox_API::API_URL . self::OAUTH_UPGRADE;
87
  $response = $this->fetch('POST', $url, '');
88
  $token = new stdClass();
89
  /*
@@ -126,17 +135,8 @@ abstract class Dropbox_ConsumerAbstract
126
  $iwp_backup_core->log('Dropbox reauthorisation needed; but we are running from cron, AJAX or the CLI, so this is not possible');
127
  $this->storage->do_unset('access_token');
128
  throw new Dropbox_Exception(sprintf(__('You need to re-authenticate with %s, as your existing credentials are not working.', 'InfiniteWP'), 'Dropbox'));
129
-
130
  return false;
131
  }
132
-
133
- public function setToken($token)
134
- {
135
-
136
- $this->token = $token;
137
-
138
- return $this;
139
- }
140
 
141
  /**
142
  * Build the user authorisation URL
@@ -150,11 +150,18 @@ abstract class Dropbox_ConsumerAbstract
150
  */
151
 
152
  global $iwp_backup_core;
153
- if (!function_exists('crypt_random_string')) $iwp_backup_core->ensure_phpseclib('Crypt_Random', 'Crypt/Random');
154
 
155
  $CSRF = base64_encode(crypt_random_string(16));
156
  $this->storage->set($CSRF,'CSRF');
157
-
 
 
 
 
 
 
 
158
  $appkey = $this->storage->get('appkey');
159
 
160
  if (!empty($appkey) && 'dropbox:' == substr($appkey, 0, 8)) {
@@ -162,12 +169,16 @@ abstract class Dropbox_ConsumerAbstract
162
  } else if (!empty($appkey)) {
163
  $key = $appkey;
164
  }
 
 
165
 
166
  $params = array(
167
  'client_id' => empty($key) ? $this->oauth2_id : $key,
168
  'response_type' => 'code',
169
  'redirect_uri' => empty($key) ? $this->callback : $this->callbackhome,
170
- 'state' => empty($key) ? $CSRF.$this->callbackhome : $CSRF,
 
 
171
  );
172
 
173
  // Build the URL and redirect the user
@@ -216,7 +227,7 @@ abstract class Dropbox_ConsumerAbstract
216
 
217
  } else {
218
  $code = base64_decode($code);
219
- $code = json_decode($code, true);
220
  }
221
 
222
  /*
@@ -226,13 +237,14 @@ abstract class Dropbox_ConsumerAbstract
226
  as far as I can tell only the oauth token is used
227
  after more testing token secret can be removed.
228
  */
229
-
230
  $token = new stdClass();
231
  $token->oauth_token_secret = $code['access_token'];
232
  $token->oauth_token = $code['access_token'];
233
  $token->account_id = $code['account_id'];
234
  $token->token_type = $code['token_type'];
235
  $token->uid = $code['uid'];
 
 
236
  $this->storage->set($token, 'access_token');
237
  $this->storage->do_unset('upgraded');
238
 
@@ -242,6 +254,49 @@ abstract class Dropbox_ConsumerAbstract
242
  throw new Dropbox_BadRequestException("No Dropbox Code found, will try to get one now", 400);
243
  }
244
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
 
246
  /**
247
  * Get the request/access token
@@ -250,10 +305,18 @@ abstract class Dropbox_ConsumerAbstract
250
  * if we have not yet started the authentication process
251
  * @return object stdClass
252
  */
253
- public function getToken()
254
  {
255
- return $this->token;
 
 
 
 
 
 
 
256
  }
 
257
  /**
258
  * Generate signed request URL
259
  * See inline comments for description
@@ -270,24 +333,40 @@ abstract class Dropbox_ConsumerAbstract
270
  $token = $this->getToken();
271
 
272
  // Prepare the standard request parameters differently for OAuth1 and OAuth2; we still need OAuth1 to make the request to the upgrade token endpoint
273
- if (!empty($token)) {
274
- $params = array(
275
- 'access_token' => $token,
276
- );
 
 
 
 
 
 
277
 
278
  /*
279
  To keep this API backwards compatible with the API v1 endpoints all v2 endpoints will also send to this method a api_v2 parameter this will then return just the access token as the signed request is not needed for any calls.
280
  */
281
 
282
- if (isset($additional['api_v2']) && $additional['api_v2'] == true) {
283
- unset($additional['api_v2']);
 
284
  if (isset($additional['content_download']) && $additional['content_download'] == true) {
285
  unset($additional['content_download']);
 
 
 
 
 
 
 
286
  $headers = array(
287
  'Authorization: Bearer '.$params['access_token'],
288
  'Content-Type:',
289
  'Dropbox-API-Arg: '.json_encode($additional),
290
  );
 
 
291
  $additional = '';
292
  } else if (isset($additional['content_upload']) && $additional['content_upload'] == true) {
293
  unset($additional['content_upload']);
@@ -308,6 +387,25 @@ abstract class Dropbox_ConsumerAbstract
308
  'postfields' => $additional,
309
  'headers' => $headers,
310
  );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
311
  }
312
  } else {
313
  // Generate a random string for the request
20
  const ACCESS_TOKEN_METHOD = 'oauth2/token';
21
  // The next endpoint only exists with APIv1
22
  const OAUTH_UPGRADE = 'oauth2/token_from_oauth1';
23
+
24
+ private $scopes = array(
25
+ 'account_info.read',
26
+ 'files.content.write',
27
+ 'files.content.read',
28
+ 'files.metadata.read',
29
+ );
30
 
31
  /**
32
  * Signature method, either PLAINTEXT or HMAC-SHA1
33
  * @var string
34
  */
35
  private $sigMethod = 'PLAINTEXT';
 
 
36
 
37
  /**
38
  * Output file handle
62
  $this->upgradeOAuth();
63
  $iwp_backup_core->log('OAuth token upgrade successful');
64
  }
65
+
66
+ if (!empty($access_token) && isset($access_token->refresh_token) && isset($access_token->expires_in)) {
67
+ if ($access_token->expires_in < time()) $this->refreshAccessToken();
68
+ }
69
 
70
  if (empty($access_token) || !isset($access_token->oauth_token)) {
71
  try {
92
  private function upgradeOAuth()
93
  {
94
  // N.B. This call only exists under API v1 - i.e. there is no APIv2 equivalent. Hence the APIv1 endpoint (API_URL) is used, and not the v2 (API_URL_V2)
95
+ $url = 'https://api.dropbox.com/1/' . self::OAUTH_UPGRADE;
96
  $response = $this->fetch('POST', $url, '');
97
  $token = new stdClass();
98
  /*
135
  $iwp_backup_core->log('Dropbox reauthorisation needed; but we are running from cron, AJAX or the CLI, so this is not possible');
136
  $this->storage->do_unset('access_token');
137
  throw new Dropbox_Exception(sprintf(__('You need to re-authenticate with %s, as your existing credentials are not working.', 'InfiniteWP'), 'Dropbox'));
 
138
  return false;
139
  }
 
 
 
 
 
 
 
 
140
 
141
  /**
142
  * Build the user authorisation URL
150
  */
151
 
152
  global $iwp_backup_core;
153
+ if (!function_exists('crypt_random_string')) $iwp_backup_core->ensure_phpseclib('Crypt_Random');
154
 
155
  $CSRF = base64_encode(crypt_random_string(16));
156
  $this->storage->set($CSRF,'CSRF');
157
+ // Prepare request parameters
158
+ /*
159
+ For OAuth v2 Dropbox needs to use a authorisation url that matches one that is set inside the
160
+ Dropbox developer console. In order to check this it needs the client ID for the OAuth v2 app
161
+ This will use the default one unless the user is using their own Dropbox App
162
+
163
+ Check if the key has dropbox: if so then remove it to stop the request from being invalid
164
+ */
165
  $appkey = $this->storage->get('appkey');
166
 
167
  if (!empty($appkey) && 'dropbox:' == substr($appkey, 0, 8)) {
169
  } else if (!empty($appkey)) {
170
  $key = $appkey;
171
  }
172
+
173
+ if ('' != $this->instance_id) $this->instance_id = ':'.$this->instance_id;
174
 
175
  $params = array(
176
  'client_id' => empty($key) ? $this->oauth2_id : $key,
177
  'response_type' => 'code',
178
  'redirect_uri' => empty($key) ? $this->callback : $this->callbackhome,
179
+ 'state' => empty($key) ? "POST:".$CSRF.$this->instance_id.$this->callbackhome : $CSRF.$this->instance_id,
180
+ 'scope' => implode(' ', $this->scopes),
181
+ 'token_access_type' => 'offline'
182
  );
183
 
184
  // Build the URL and redirect the user
227
 
228
  } else {
229
  $code = base64_decode($code);
230
+ $code = json_decode($code, true);
231
  }
232
 
233
  /*
237
  as far as I can tell only the oauth token is used
238
  after more testing token secret can be removed.
239
  */
 
240
  $token = new stdClass();
241
  $token->oauth_token_secret = $code['access_token'];
242
  $token->oauth_token = $code['access_token'];
243
  $token->account_id = $code['account_id'];
244
  $token->token_type = $code['token_type'];
245
  $token->uid = $code['uid'];
246
+ $token->refresh_token = $code['refresh_token'];
247
+ $token->expires_in = time() + $code['expires_in'] - 30;
248
  $this->storage->set($token, 'access_token');
249
  $this->storage->do_unset('upgraded');
250
 
254
  throw new Dropbox_BadRequestException("No Dropbox Code found, will try to get one now", 400);
255
  }
256
  }
257
+
258
+ /**
259
+ * This function will make a request to the auth server sending the users refresh token to get a new access token
260
+ *
261
+ * @return void
262
+ */
263
+ public function refreshAccessToken() {
264
+ global $iwp_backup_core;
265
+
266
+ $access_token = $this->storage->get('access_token');
267
+
268
+ $params = array(
269
+ 'grant_type' => 'refresh_token',
270
+ 'refresh_token' => $access_token->refresh_token,
271
+ );
272
+
273
+ $url = IWP_MMB_Dropbox_API::API_URL_V2 . self::ACCESS_TOKEN_METHOD;
274
+
275
+ $response = $this->fetch('POST', $url, '' , $params);
276
+
277
+ if ("200" != $response['code']) {
278
+ $iwp_backup_core->log('Failed to refresh access token error code: '.$response['code']);
279
+ return;
280
+ }
281
+
282
+ if (empty($response['body'])) {
283
+ $iwp_backup_core->log('Failed to refresh access token empty response body');
284
+ return;
285
+ }
286
+
287
+ $body = $response['body'];
288
+
289
+ if (isset($body->access_token) && isset($body->expires_in)) {
290
+ $access_token->oauth_token_secret = $body->access_token;
291
+ $access_token->oauth_token = $body->access_token;
292
+ $access_token->expires_in = time() + $body->expires_in - 30;
293
+ $this->storage->set($access_token, 'access_token');
294
+ $iwp_backup_core->log('Successfully updated and refreshed the access token');
295
+ } else {
296
+ $iwp_backup_core->log('Failed to refresh access token missing token and expiry: '.json_encode($body));
297
+ return;
298
+ }
299
+ }
300
 
301
  /**
302
  * Get the request/access token
305
  * if we have not yet started the authentication process
306
  * @return object stdClass
307
  */
308
+ private function getToken()
309
  {
310
+ if (!$token = $this->storage->get('access_token')) {
311
+ if (!$token = $this->storage->get('request_token')) {
312
+ $token = new stdClass();
313
+ $token->oauth_token = null;
314
+ $token->oauth_token_secret = null;
315
+ }
316
+ }
317
+ return $token;
318
  }
319
+
320
  /**
321
  * Generate signed request URL
322
  * See inline comments for description
333
  $token = $this->getToken();
334
 
335
  // Prepare the standard request parameters differently for OAuth1 and OAuth2; we still need OAuth1 to make the request to the upgrade token endpoint
336
+ if (isset($token)) {
337
+ if (isset($token->oauth_token)) {
338
+ $params = array(
339
+ 'access_token' => $token->oauth_token,
340
+ );
341
+ }else{
342
+ $params = array(
343
+ 'access_token' => $token,
344
+ );
345
+ }
346
 
347
  /*
348
  To keep this API backwards compatible with the API v1 endpoints all v2 endpoints will also send to this method a api_v2 parameter this will then return just the access token as the signed request is not needed for any calls.
349
  */
350
 
351
+ if (isset($additional['api_v2']) && $additional['api_v2'] == true && !isset($additional['refresh_token'])) {
352
+ unset($additional['api_v2']);
353
+ if (isset($additional['timeout'])) unset($additional['timeout']);
354
  if (isset($additional['content_download']) && $additional['content_download'] == true) {
355
  unset($additional['content_download']);
356
+ $extra_headers = array();
357
+ if (isset($additional['headers'])) {
358
+ foreach ($additional['headers'] as $key => $header) {
359
+ $extra_headers[] = $header;
360
+ }
361
+ unset($additional['headers']);
362
+ }
363
  $headers = array(
364
  'Authorization: Bearer '.$params['access_token'],
365
  'Content-Type:',
366
  'Dropbox-API-Arg: '.json_encode($additional),
367
  );
368
+
369
+ $headers = array_merge($headers, $extra_headers);
370
  $additional = '';
371
  } else if (isset($additional['content_upload']) && $additional['content_upload'] == true) {
372
  unset($additional['content_upload']);
387
  'postfields' => $additional,
388
  'headers' => $headers,
389
  );
390
+ } elseif (isset($additional['refresh_token'])) {
391
+ $extra_headers = array();
392
+ if (isset($additional['headers']) && !empty($additional['headers'])) {
393
+ foreach ($additional['headers'] as $key => $header) {
394
+ $extra_headers[] = $key.': '.$header;
395
+ }
396
+ unset($additional['headers']);
397
+ }
398
+ $headers = array();
399
+ $headers[] = 'Authorization: Basic ' . base64_encode($this->consumerKey . ':' . $this->consumerSecret);
400
+ // $headers[] = 'Content-Type: application/x-www-form-urlencoded';
401
+ // $headers[] = 'Content-Type: application/json';
402
+ $headers = array_merge($headers, $extra_headers);
403
+
404
+ return array(
405
+ 'url' => $url . $call,
406
+ 'postfields' => $additional,
407
+ 'headers' => $headers,
408
+ );
409
  }
410
  } else {
411
  // Generate a random string for the request
lib/Dropbox2/OAuth/Consumer/Curl.php CHANGED
@@ -35,7 +35,7 @@ class Dropbox_Curl extends Dropbox_ConsumerAbstract
35
  * @param \Dropbox\OAuth\Consumer\StorageInterface $storage
36
  * @param string $callback
37
  */
38
- public function __construct($key, $oauth2_id, $secret, Dropbox_StorageInterface $storage, $callback = null, $callbackhome = null, $deauthenticate = false)
39
  {
40
  // Check the cURL extension is loaded
41
  if (!extension_loaded('curl')) {
@@ -48,12 +48,15 @@ class Dropbox_Curl extends Dropbox_ConsumerAbstract
48
  $this->storage = $storage;
49
  $this->callback = $callback;
50
  $this->callbackhome = $callbackhome;
 
51
 
52
- // if ($deauthenticate) {
53
- // $this->deauthenticate();
54
- // } else {
55
- // $this->authenticate();
56
- // }
 
 
57
  }
58
 
59
  /**
@@ -65,11 +68,11 @@ class Dropbox_Curl extends Dropbox_ConsumerAbstract
65
  * @param array $additional Additional parameters
66
  * @return string|object stdClass
67
  */
68
- public function fetch($method, $url, $call, array $additional = array())
69
  {
70
  // Get the signed request URL
71
  $request = $this->getSignedRequest($method, $url, $call, $additional);
72
-
73
  // Initialise and execute a cURL request
74
  $handle = curl_init($request['url']);
75
 
@@ -104,8 +107,6 @@ class Dropbox_Curl extends Dropbox_ConsumerAbstract
104
  }
105
  }
106
  }
107
-
108
- // if (isset($request['headers'])) $options[CURLOPT_HTTPHEADER] = $request['headers'];
109
 
110
  /*
111
  Add check to see if it's an API v2 call if so then json encode the contents. This is so that it is backwards compatible with API v1 endpoints.
@@ -119,6 +120,7 @@ class Dropbox_Curl extends Dropbox_ConsumerAbstract
119
  $request['postfields'] = json_encode(null);
120
  }
121
  }
 
122
  if (isset($request['headers']) && !empty($request['headers'])) $options[CURLOPT_HTTPHEADER] = $request['headers'];
123
 
124
  if ($method == 'GET' && $this->outFile) { // GET
@@ -141,7 +143,15 @@ class Dropbox_Curl extends Dropbox_ConsumerAbstract
141
  $options[CURLOPT_POSTFIELDS] = $this->inFile;
142
  } elseif ($method == 'POST') { // POST
143
  $options[CURLOPT_POST] = true;
144
- $options[CURLOPT_POSTFIELDS] = $request['postfields'];
 
 
 
 
 
 
 
 
145
  } elseif ($method == 'PUT' && $this->inFile) { // PUT
146
  $options[CURLOPT_PUT] = true;
147
  $options[CURLOPT_INFILE] = $this->inFile;
@@ -151,6 +161,10 @@ class Dropbox_Curl extends Dropbox_ConsumerAbstract
151
  $this->inFile = null;
152
  }
153
 
 
 
 
 
154
  // Set the cURL options at once
155
  curl_setopt_array($handle, $options);
156
  // Execute, get any error and close
@@ -167,7 +181,6 @@ class Dropbox_Curl extends Dropbox_ConsumerAbstract
167
  // Parse the response if it is a string
168
  if (is_string($response)) {
169
  $response = $this->parse($response);
170
- $response['code'] = (!empty($response['code'])) ? $response['code'] : $getinfo['http_code'];
171
  }
172
 
173
  // Set the last response
@@ -191,12 +204,13 @@ class Dropbox_Curl extends Dropbox_ConsumerAbstract
191
  if (strpos($array[0] , 'incorrect_offset') !== false) {
192
  $message = json_encode($array);
193
  } elseif (strpos($array[0] , 'lookup_failed') !== false ) {
194
- //re-structure the array so it is correctly formatted for API
195
- //Note: Dropbox v2 returns different errors at different stages hence this fix
196
  $correctOffset = array(
197
  '0' => $array[1]->{'.tag'},
198
- '1' => $array[1]->correct_offset
199
  );
 
 
200
 
201
  $message = json_encode($correctOffset);
202
  } else {
@@ -216,6 +230,7 @@ class Dropbox_Curl extends Dropbox_ConsumerAbstract
216
  case 304:
217
  throw new Dropbox_NotModifiedException($message, 304);
218
  case 400:
 
219
  throw new Dropbox_BadRequestException($message, 400);
220
  case 404:
221
  throw new Dropbox_NotFoundException($message, 404);
@@ -224,8 +239,8 @@ class Dropbox_Curl extends Dropbox_ConsumerAbstract
224
  case 415:
225
  throw new Dropbox_UnsupportedMediaTypeException($message, 415);
226
  case 401:
227
- //401 means oauth token is expired continue to manually handle the exception depending on the situation
228
- break;
229
  case 409:
230
  //409 in API V2 every error will return with a 409 to find out what the error is the error description should be checked.
231
  throw new Dropbox_Exception($message, $code);
@@ -253,14 +268,14 @@ class Dropbox_Curl extends Dropbox_ConsumerAbstract
253
 
254
  // If the status code is 100, the API server must send a final response
255
  // We need to explode the response again to get the actual response
256
- if (preg_match('#^HTTP/1.1 100#i', $lines[0])) {
257
  list($headers, $response) = explode("\r\n\r\n", $response, 2);
258
  $lines = explode("\r\n", $headers);
259
  }
260
 
261
  // Get the HTTP response code from the first line
262
  $first = array_shift($lines);
263
- $pattern = '#^HTTP/1.1 ([0-9]{3})#i';
264
  preg_match($pattern, $first, $matches);
265
  $code = $matches[1];
266
 
@@ -279,7 +294,7 @@ class Dropbox_Curl extends Dropbox_ConsumerAbstract
279
 
280
  if (is_string($body)) {
281
  $body_lines = explode("\r\n", $body);
282
- if (preg_match('#^HTTP/1.1 100#i', $body_lines[0]) && preg_match('#^HTTP/1.#i', $body_lines[2])) {
283
  return $this->parse($body);
284
  }
285
  }
35
  * @param \Dropbox\OAuth\Consumer\StorageInterface $storage
36
  * @param string $callback
37
  */
38
+ public function __construct($key, $oauth2_id, $secret, Dropbox_StorageInterface $storage, $callback = null, $callbackhome = null, $deauthenticate = false, $instance_id = '', $old_auth = false)
39
  {
40
  // Check the cURL extension is loaded
41
  if (!extension_loaded('curl')) {
48
  $this->storage = $storage;
49
  $this->callback = $callback;
50
  $this->callbackhome = $callbackhome;
51
+ $this->instance_id = $instance_id;
52
 
53
+ if ($old_auth == false) {
54
+ if ($deauthenticate) {
55
+ $this->deauthenticate();
56
+ } else {
57
+ $this->authenticate();
58
+ }
59
+ }
60
  }
61
 
62
  /**
68
  * @param array $additional Additional parameters
69
  * @return string|object stdClass
70
  */
71
+ public function fetch($method, $url, $call, array $additional = array(), $retry_with_header = false)
72
  {
73
  // Get the signed request URL
74
  $request = $this->getSignedRequest($method, $url, $call, $additional);
75
+
76
  // Initialise and execute a cURL request
77
  $handle = curl_init($request['url']);
78
 
107
  }
108
  }
109
  }
 
 
110
 
111
  /*
112
  Add check to see if it's an API v2 call if so then json encode the contents. This is so that it is backwards compatible with API v1 endpoints.
120
  $request['postfields'] = json_encode(null);
121
  }
122
  }
123
+
124
  if (isset($request['headers']) && !empty($request['headers'])) $options[CURLOPT_HTTPHEADER] = $request['headers'];
125
 
126
  if ($method == 'GET' && $this->outFile) { // GET
143
  $options[CURLOPT_POSTFIELDS] = $this->inFile;
144
  } elseif ($method == 'POST') { // POST
145
  $options[CURLOPT_POST] = true;
146
+ if (!empty($request['postfields'])) {
147
+ $options[CURLOPT_POSTFIELDS] = $request['postfields'];
148
+ } elseif (empty($additional['content_upload'])) {
149
+ // JSON representation of nullity
150
+ $options[CURLOPT_POSTFIELDS] = 'null';
151
+ } elseif ($retry_with_header) {
152
+ // It's a content upload, and there's no data. Versions of php-curl differ as to whether they add a Content-Length header automatically or not. Dropbox complains if it's not there. Here we have had a Dropbox 400 bad request returned so we try again with the header
153
+ $options[CURLOPT_HTTPHEADER] = array_merge($options[CURLOPT_HTTPHEADER], array('Content-Length: 0'));
154
+ }
155
  } elseif ($method == 'PUT' && $this->inFile) { // PUT
156
  $options[CURLOPT_PUT] = true;
157
  $options[CURLOPT_INFILE] = $this->inFile;
161
  $this->inFile = null;
162
  }
163
 
164
+ if (isset($additional['timeout'])) {
165
+ $options[CURLOPT_TIMEOUT] = $additional['timeout'];
166
+ }
167
+
168
  // Set the cURL options at once
169
  curl_setopt_array($handle, $options);
170
  // Execute, get any error and close
181
  // Parse the response if it is a string
182
  if (is_string($response)) {
183
  $response = $this->parse($response);
 
184
  }
185
 
186
  // Set the last response
204
  if (strpos($array[0] , 'incorrect_offset') !== false) {
205
  $message = json_encode($array);
206
  } elseif (strpos($array[0] , 'lookup_failed') !== false ) {
207
+ // re-structure the array so it is correctly formatted for API
208
+ // Note: Dropbox v2 returns different errors at different stages hence this fix
209
  $correctOffset = array(
210
  '0' => $array[1]->{'.tag'},
 
211
  );
212
+ // the lookup_failed response doesn't always return a correct_offset this happens when the lookup fails because the session has been closed e.g the file has already been uploaded but the response didn't make it back to the client so we try again
213
+ if (isset($array[1]->correct_offset)) $correctOffset['1'] = $array[1]->correct_offset;
214
 
215
  $message = json_encode($correctOffset);
216
  } else {
230
  case 304:
231
  throw new Dropbox_NotModifiedException($message, 304);
232
  case 400:
233
+ if (!$retry_with_header) return $this->fetch($method, $url, $call, $additional, true);
234
  throw new Dropbox_BadRequestException($message, 400);
235
  case 404:
236
  throw new Dropbox_NotFoundException($message, 404);
239
  case 415:
240
  throw new Dropbox_UnsupportedMediaTypeException($message, 415);
241
  case 401:
242
+ //401 means oauth token is expired continue to manually handle the exception depending on the situation
243
+ break;
244
  case 409:
245
  //409 in API V2 every error will return with a 409 to find out what the error is the error description should be checked.
246
  throw new Dropbox_Exception($message, $code);
268
 
269
  // If the status code is 100, the API server must send a final response
270
  // We need to explode the response again to get the actual response
271
+ if (preg_match('#^HTTP/[\.\d]+ 100#i', $lines[0])) {
272
  list($headers, $response) = explode("\r\n\r\n", $response, 2);
273
  $lines = explode("\r\n", $headers);
274
  }
275
 
276
  // Get the HTTP response code from the first line
277
  $first = array_shift($lines);
278
+ $pattern = '#^HTTP/[\.\d]+ ([0-9]{3})#i';
279
  preg_match($pattern, $first, $matches);
280
  $code = $matches[1];
281
 
294
 
295
  if (is_string($body)) {
296
  $body_lines = explode("\r\n", $body);
297
+ if (preg_match('#^HTTP/[\.\d]+ 100#i', $body_lines[0]) && preg_match('#^HTTP/\d#i', $body_lines[2])) {
298
  return $this->parse($body);
299
  }
300
  }
lib/Dropbox2/OAuth/Consumer/WordPress.php CHANGED
@@ -2,7 +2,6 @@
2
 
3
  /**
4
  * OAuth consumer using the WordPress API
5
- * @author David Anderson <david@updraftplus.com>
6
  * @link https://github.com/DavidAnderson684/Dropbox
7
  * @package Dropbox\OAuth
8
  * @subpackage Consumer
2
 
3
  /**
4
  * OAuth consumer using the WordPress API
 
5
  * @link https://github.com/DavidAnderson684/Dropbox
6
  * @package Dropbox\OAuth
7
  * @subpackage Consumer
lib/Dropbox2/OAuth/Storage/Encrypter.php CHANGED
@@ -9,14 +9,6 @@
9
  * @subpackage Storage
10
  */
11
 
12
- /*
13
- Using this was fairly pointless (it encrypts storage credentials at rest). But, it's implemented now, so needs supporting.
14
- Investigation shows that mcrypt and phpseclib native encryption using different padding schemes.
15
- 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.
16
- 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.
17
- 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.
18
- */
19
-
20
  class Dropbox_Encrypter
21
  {
22
  // Encryption settings - default settings yield encryption to AES (256-bit) standard
@@ -57,12 +49,18 @@ class Dropbox_Encrypter
57
  {
58
 
59
  // Encryption: we always use phpseclib for this
60
-
61
  global $iwp_backup_core;
62
- $iwp_backup_core->ensure_phpseclib('Crypt_AES', 'Crypt/AES');
63
- $iwp_backup_core->ensure_phpseclib('Crypt_Rijndael', 'Crypt/Rijndael');
 
 
 
 
 
 
 
64
 
65
- if (!function_exists('crypt_random_string')) require_once($GLOBALS['iwp_mmb_plugin_dir'].'/vendor/phpseclib/phpseclib/phpseclib/Crypt/Random.php');
66
 
67
  $iv = crypt_random_string(self::IV_SIZE);
68
 
@@ -93,10 +91,11 @@ class Dropbox_Encrypter
93
  $cipherText = substr($cipherText, self::IV_SIZE);
94
 
95
  if (function_exists('mcrypt_decrypt')) {
 
96
  $token = @mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $this->key, $cipherText, MCRYPT_MODE_CBC, $iv);
97
  } else {
98
  global $iwp_backup_core;
99
- $iwp_backup_core->ensure_phpseclib('Crypt_Rijndael', 'Crypt/Rijndael');
100
 
101
  $rijndael = new Crypt_Rijndael();
102
  $rijndael->setKey($this->key);
9
  * @subpackage Storage
10
  */
11
 
 
 
 
 
 
 
 
 
12
  class Dropbox_Encrypter
13
  {
14
  // Encryption settings - default settings yield encryption to AES (256-bit) standard
49
  {
50
 
51
  // Encryption: we always use phpseclib for this
 
52
  global $iwp_backup_core;
53
+ $ensure_phpseclib = $iwp_backup_core->ensure_phpseclib('Crypt_AES');
54
+
55
+ if (is_wp_error($ensure_phpseclib)) {
56
+ $iwp_backup_core->log("Failed to load phpseclib classes (".$ensure_phpseclib->get_error_code()."): ".$ensure_phpseclib->get_error_message());
57
+ $iwp_backup_core->log("Failed to load phpseclib classes (".$ensure_phpseclib->get_error_code()."): ".$ensure_phpseclib->get_error_message(), 'error');
58
+ return false;
59
+ }
60
+
61
+ $iwp_backup_core->ensure_phpseclib('Crypt_Rijndael');
62
 
63
+ if (!function_exists('crypt_random_string')) require_once($GLOBALS['iwp_mmb_plugin_dir'].'/lib/phpseclib/phpseclib/phpseclib/Crypt/Random.php');
64
 
65
  $iv = crypt_random_string(self::IV_SIZE);
66
 
91
  $cipherText = substr($cipherText, self::IV_SIZE);
92
 
93
  if (function_exists('mcrypt_decrypt')) {
94
+ // @codingStandardsIgnoreLine
95
  $token = @mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $this->key, $cipherText, MCRYPT_MODE_CBC, $iv);
96
  } else {
97
  global $iwp_backup_core;
98
+ $iwp_backup_core->ensure_phpseclib('Crypt_Rijndael');
99
 
100
  $rijndael = new Crypt_Rijndael();
101
  $rijndael->setKey($this->key);
lib/Dropbox2/OAuth/Storage/WordPress.php CHANGED
@@ -4,8 +4,6 @@
4
  * OAuth storage handler using WordPress options
5
  * This can only be used if you have a WordPress environment loaded, such that the (get|update|delete)_option functions are available
6
  * See an example usage in http://wordpress.org/extend/plugins/updraftplus
7
- * @author David Anderson <david@updraftplus.com>
8
- * @link https://updraftplus.com
9
  * @package Dropbox\Oauth
10
  * @subpackage Storage
11
  */
@@ -46,9 +44,7 @@ class Dropbox_WordPress implements Dropbox_StorageInterface
46
  $this->encrypter = $encrypter;
47
  }
48
 
49
- if ($backup_module_object instanceof IWP_MMB_UploadModule) {
50
- $this->backup_module_object = $backup_module_object;
51
- }
52
 
53
  $this->option_name_prefix = $option_name_prefix;
54
  $this->option_array = $option_array;
@@ -70,7 +66,11 @@ class Dropbox_WordPress implements Dropbox_StorageInterface
70
  if ($type == 'request_token' || $type == 'access_token'){
71
  if (!empty($opts[$this->option_name_prefix.$type])) {
72
  $gettoken = $opts[$this->option_name_prefix.$type];
73
- $token = $gettoken;
 
 
 
 
74
  return $token;
75
  }
76
  } else {
@@ -99,7 +99,9 @@ class Dropbox_WordPress implements Dropbox_StorageInterface
99
  $opts = $this->backup_module_object->get_options();
100
 
101
  if ($type == 'access_token'){
102
- $token = $this->encrypt($token);
 
 
103
  $opts[$this->option_name_prefix.$type] = $token;
104
  } else if ($type == 'request_token' ) {
105
  $opts[$this->option_name_prefix.$type] = $token;
4
  * OAuth storage handler using WordPress options
5
  * This can only be used if you have a WordPress environment loaded, such that the (get|update|delete)_option functions are available
6
  * See an example usage in http://wordpress.org/extend/plugins/updraftplus
 
 
7
  * @package Dropbox\Oauth
8
  * @subpackage Storage
9
  */
44
  $this->encrypter = $encrypter;
45
  }
46
 
47
+ $this->backup_module_object = $backup_module_object;
 
 
48
 
49
  $this->option_name_prefix = $option_name_prefix;
50
  $this->option_array = $option_array;
66
  if ($type == 'request_token' || $type == 'access_token'){
67
  if (!empty($opts[$this->option_name_prefix.$type])) {
68
  $gettoken = $opts[$this->option_name_prefix.$type];
69
+ if (!empty($opts['email'])) {
70
+ $token = $this->decrypt($gettoken);
71
+ }else{
72
+ $token = $gettoken;
73
+ }
74
  return $token;
75
  }
76
  } else {
99
  $opts = $this->backup_module_object->get_options();
100
 
101
  if ($type == 'access_token'){
102
+ if (!empty($opts['email'])) {
103
+ $token = $this->encrypt($token);
104
+ }
105
  $opts[$this->option_name_prefix.$type] = $token;
106
  } else if ($type == 'request_token' ) {
107
  $opts[$this->option_name_prefix.$type] = $token;
lib/sftp.php CHANGED
@@ -335,6 +335,8 @@ class IWP_MMB_RemoteStorage_sftp extends IWP_MMB_RemoteStorage_Extension {
335
  }
336
  }
337
 
 
 
338
  if (!$this->ssh->login($user, $pass)) {
339
  $error_data = null;
340
  $message = 'SSH 2 login failed';
335
  }
336
  }
337
 
338
+ // Ensure phpseclib Crypt_Blowfish is loaded, over PEAR's
339
+ $iwp_backup_core->ensure_phpseclib('Crypt_Blowfish', 'Crypt/Blowfish');
340
  if (!$this->ssh->login($user, $pass)) {
341
  $error_data = null;
342
  $message = 'SSH 2 login failed';
pclzip.class.php CHANGED
@@ -3440,7 +3440,11 @@ endif;
3440
  }
3441
 
3442
  // ----- Read the file content
 
3443
  $v_content = @fread($v_file, $p_header['size']);
 
 
 
3444
 
3445
  // ----- Close the file
3446
  @fclose($v_file);
3440
  }
3441
 
3442
  // ----- Read the file content
3443
+ if ($p_header['size'] > 0) {
3444
  $v_content = @fread($v_file, $p_header['size']);
3445
+ }else{
3446
+ $v_content = '';
3447
+ }
3448
 
3449
  // ----- Close the file
3450
  @fclose($v_file);
plugin.compatibility.class.php CHANGED
@@ -139,9 +139,9 @@ class IWP_MMB_FixCompatibility
139
  return null;
140
  }
141
 
142
- public function fixPantheonGlobals()
143
  {
144
- if (!empty($_ENV['PANTHEON_ENVIRONMENT']) && !isset($GLOBALS['hook_suffix'])) {
145
  $GLOBALS['hook_suffix'] = null;
146
  }
147
  }
139
  return null;
140
  }
141
 
142
+ public function fixGlobals()
143
  {
144
+ if (!isset($GLOBALS['hook_suffix'])) {
145
  $GLOBALS['hook_suffix'] = null;
146
  }
147
  }
readme.txt CHANGED
@@ -1,8 +1,8 @@
1
  === InfiniteWP Client ===
2
- Contributors: infinitewp
3
  Tags: admin, administration, amazon, api, authentication, automatic, dashboard, dropbox, events, integration, manage, multisite, multiple, notification, performance, s3, security, seo, stats, tracking, infinitewp, updates, backup, restore, iwp, infinite
4
  Requires at least: 3.1
5
- Tested up to: 5.7.2
6
  Stable tag: trunk
7
 
8
  Install this plugin on unlimited sites and manage them all from a central dashboard.
@@ -48,6 +48,16 @@ Credits: [Vladimir Prelovac](http://prelovac.com/vladimir) for his worker plugin
48
 
49
  == Changelog ==
50
 
 
 
 
 
 
 
 
 
 
 
51
  = 1.9.4.11 - Jun 16th 2021 =
52
  * Improvement: Amazon s3 library updated.
53
  * Improvement: Wordfence data not correctly showing in Client report due to the Wordfence recent release.
1
  === InfiniteWP Client ===
2
+ Contributors: infinitewp, amritanandh, rajkuppus
3
  Tags: admin, administration, amazon, api, authentication, automatic, dashboard, dropbox, events, integration, manage, multisite, multiple, notification, performance, s3, security, seo, stats, tracking, infinitewp, updates, backup, restore, iwp, infinite
4
  Requires at least: 3.1
5
+ Tested up to: 5.9
6
  Stable tag: trunk
7
 
8
  Install this plugin on unlimited sites and manage them all from a central dashboard.
48
 
49
  == Changelog ==
50
 
51
+ = 1.9.6 - Feb 14th 2022 =
52
+ * Feature: Added support for Litespeed Cache.
53
+ * Improvement: Ensure phpseclib Crypt_Blowfish is loaded over PEAR’s version.
54
+ * Improvement: Enabled support for new Dropbox OAuth Authentication.
55
+ * Fix: Enabled version number for InfiniteWP MU plugin loader.
56
+ * Fix: Undefined array key “hook_suffix” warning.
57
+ * Fix: Delete SFTP test backup file on the remote server.
58
+ * Fix: PPL addon editor image not uploaded. (issue happening from 1.9.4.9).
59
+ * Fix: Fatal error while backing up a 0kb file using the single call method on site installed on site with php8 server.
60
+
61
  = 1.9.4.11 - Jun 16th 2021 =
62
  * Improvement: Amazon s3 library updated.
63
  * Improvement: Wordfence data not correctly showing in Client report due to the Wordfence recent release.