PluginProbe ʕ •ᴥ•ʔ
Backup Migration / 2.1.6
Backup Migration v2.1.6
2.1.6 2.1.5.2 trunk 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.6.1 1.4.7 1.4.8 1.4.9 1.4.9.1 2.0.0 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.5.1
backup-backup / includes / offline.php
backup-backup / includes Last commit date
banner 3 weeks ago bodies 3 weeks ago check 3 weeks ago cli 3 weeks ago cron 3 weeks ago dashboard 3 weeks ago database 3 weeks ago external 3 weeks ago extracter 3 weeks ago htaccess 3 weeks ago notices 3 weeks ago progress 3 weeks ago scanner 3 weeks ago services 3 weeks ago staging 3 weeks ago traits 3 weeks ago uploader 3 weeks ago vendor 3 weeks ago zipper 3 weeks ago .htaccess 3 weeks ago activation.php 3 weeks ago ajax.php 3 weeks ago ajax_offline.php 3 weeks ago analyst.php 3 weeks ago backup-process.php 3 weeks ago class-backup-method-mananger.php 3 weeks ago cli-handler.php 3 weeks ago compatibility.php 3 weeks ago config.php 3 weeks ago constants.php 3 weeks ago file-explorer.php 3 weeks ago initializer.php 3 weeks ago logger.php 3 weeks ago offline.php 3 weeks ago
offline.php
201 lines
1 <?php
2
3 // Namespace
4 namespace BMI\Plugin;
5 use BMI\Plugin\Backup_Migration_Plugin as BMP;
6 use BMI\Plugin\BMI_Logger as Logger;
7 // Exit on direct access
8 if (!defined('ABSPATH')) {
9 exit;
10 }
11
12 /**
13 * Offline Methods Manager
14 */
15 class BMI_Offline {
16
17 public $ajaxInserted = false;
18
19 /**
20 * __construct - Initializer (loads offline modules)
21 */
22 function __construct() {
23 add_action('bmi_ajax_offline', function($post=[]){
24 if (BMI_DEBUG)
25 Logger::error("FREE AJAX OFFLINE");
26 require_once BMI_INCLUDES . '/ajax_offline.php';
27 $ajaxoffline = new BMI_Ajax_Offline($post);
28 });
29 add_action('wp_ajax_bmip_keepalive', [&$this, 'initializeOfflineAjax']);
30 add_action('wp_ajax_nopriv_bmip_keepalive', [&$this, 'initializeOfflineAjax']);
31
32 // Handle Auth Handshake For M2M Connection (Ping server)
33 add_action('wp_ajax_nopriv_bmip_auth_handshake', [&$this, 'bmip_handle_handshake_request']);
34 add_action('wp_ajax_bmip_auth_handshake', [&$this, 'bmip_handle_handshake_request']);
35
36 if (is_user_logged_in() && current_user_can('administrator')) {
37 add_action('wp_ajax_backup_migration', [&$this, 'initializeOfflineAjax']);
38 }
39
40 add_filter('allowed_http_origins', function ($origins) {
41 $origins[] = 'https://backupbliss.com';
42 $origins[] = 'https://api.backupbliss.com';
43 return $origins;
44 });
45
46 // $TBU = get_option('bmip_to_be_uploaded', false);
47 // if ($TBU != false && (sizeof($TBU['current_upload']) > 0 || sizeof($TBU['queue']) > 0)) {
48
49 // }
50
51 add_action('admin_footer', [&$this, 'keepAliveJS']);
52
53 }
54
55 /**
56 * initializeOfflineAjax - Initialized Offline handlers for Ajax
57 *
58 * @return void
59 */
60 public function initializeOfflineAjax() {
61
62
63 // Check if the request comes from a logged-in admin (Browser context)
64 // OR from the Ping Server (M2M context)
65 $is_admin = current_user_can('manage_options') && check_ajax_referer('backup-migration-ajax', 'nonce', false);
66 $is_ping_server = $this->verify_ping_server_request();
67
68 if (!$is_admin && !$is_ping_server) {
69 wp_send_json_error('Unauthorized access', 403);
70 return;
71 }
72 // if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest') {
73
74 // Extend execution time
75 if (BMP::isFunctionEnabled('headers_sent') && BMP::isFunctionEnabled('session_status')) {
76 if (!headers_sent() && session_status() === PHP_SESSION_DISABLED) {
77 if (BMP::isFunctionEnabled('ignore_user_abort')) @ignore_user_abort(true);
78 if (BMP::isFunctionEnabled('set_time_limit')) @set_time_limit(16000);
79 if (BMP::isFunctionEnabled('ini_set')) {
80 @ini_set('max_execution_time', '259200');
81 @ini_set('max_input_time', '259200');
82 }
83 }
84 }
85
86 if ((isset($_GET['token']) && ($_GET['token'] == 'bmip' || $_GET['token'] == 'bmi') && isset($_GET['f']))) {
87
88 if (empty($_GET)) return;
89
90 // Sanitize User Input
91 $post = BMP::sanitize($_GET);
92
93 } else if ((isset($_POST['token']) && ($_POST['token'] == 'bmip' || $_POST['token'] == 'bmi') && isset($_POST['f']))) {
94
95 if (empty($_POST)) return;
96
97 // Sanitize User Input
98 $post = BMP::sanitize($_POST);
99
100 }
101
102 if (!empty($post)) {
103 do_action("bmi_ajax_offline", $post);
104 }
105
106 // Execution error due to time limit
107 // register_shutdown_function([$this, 'execution_shutdown']);
108
109 // }
110
111 }
112
113 /**
114 * Verifies the Ping Server handshake.
115 * @return bool true if the request is verified, otherwise it sends a JSON error response and exits.
116 */
117 private function verify_ping_server_request() {
118 $stored_sk = get_option('bmi_sk_keepalive');
119 if (!isset($_SERVER['CONTENT_TYPE']) || stripos($_SERVER['CONTENT_TYPE'], 'application/json') === false) {
120 return false;
121 }
122 $raw = file_get_contents('php://input');
123 $data = json_decode($raw, true);
124 if (json_last_error() !== JSON_ERROR_NONE) {
125 return false;
126 }
127
128 $request_sk = sanitize_text_field( wp_unslash( isset($data['sk']) ? $data['sk'] : '' ) );
129
130 if (empty($stored_sk) || empty($request_sk)) {
131 return false;
132 }
133
134 // Constant-Time Comparison (Prevents Timing Attacks) when possible
135 if (!hash_equals($stored_sk, $request_sk)) {
136 return false;
137 }
138
139 update_option('bmi_cron_last_ping_time', current_time('timestamp'));
140
141 return true;
142 }
143
144 public function keepAliveJS() {
145 if ($this->ajaxInserted) return;
146
147 ?>
148 <script defer type="text/javascript" id="bmip-js-inline-remove-js">
149 function objectToQueryString(obj){
150 return Object.keys(obj).map(key => key + '=' + obj[key]).join('&');
151 }
152
153 function globalBMIKeepAlive() {
154 let xhr = new XMLHttpRequest();
155 let data = { action: "bmip_keepalive", token: "bmip", f: "refresh", nonce: "<?php echo esc_js( wp_create_nonce( 'backup-migration-ajax' ) ); ?>" };
156 let url = '<?php echo esc_url_raw( admin_url("admin-ajax.php") ); ?>' + '?' + objectToQueryString(data);
157 xhr.open('POST', url, true);
158 xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
159 xhr.onreadystatechange = function () {
160 if (xhr.readyState === 4) {
161 let response;
162 if (response = JSON.parse(xhr.responseText)) {
163 if (typeof response.status != 'undefined' && response.status === 'success') {
164 //setTimeout(globalBMIKeepAlive, 3000);
165 } else {
166 //setTimeout(globalBMIKeepAlive, 20000);
167 }
168 }
169 }
170 };
171
172 xhr.send(JSON.stringify(data));
173 }
174
175 document.querySelector('#bmip-js-inline-remove-js').remove();
176 </script>
177 <?php
178
179 $this->ajaxInserted = true;
180 }
181
182 function bmip_handle_handshake_request() {
183 $incoming_sk = isset($_POST['sk']) ? sanitize_text_field($_POST['sk']) : '';
184 $challenge = isset($_POST['challenge']) ? sanitize_text_field($_POST['challenge']) : '';
185
186 $stored_sk = get_option('bmi_sk_keepalive');
187
188 if ( ! empty($stored_sk) && ! empty($incoming_sk) && hash_equals($stored_sk, $incoming_sk) ) {
189
190 header('Content-Type: text/plain');
191 echo esc_html( $challenge );
192 exit;
193
194 } else {
195 header('HTTP/1.0 403 Forbidden');
196 echo 'Invalid Handshake';
197 exit;
198 }
199 }
200 }
201