transport = $transport instanceof Akkedli_V2_Enrollment_Transport ? $transport : new Akkedli_V2_Enrollment_Transport(); add_action('admin_post_' . self::ACTION, array($this, 'handle_admin_post')); } public function handle_admin_post() { if (!isset($_SERVER['REQUEST_METHOD']) || 'POST' !== strtoupper(sanitize_text_field(wp_unslash($_SERVER['REQUEST_METHOD'])))) { $this->redirect('error'); } if (!current_user_can('manage_woocommerce')) { wp_die(esc_html__('You are not allowed to manage this connection.', 'akkedli-connector'), esc_html__('Permission denied', 'akkedli-connector'), array('response' => 403)); } $nonce = isset($_POST[self::NONCE_FIELD]) && is_string($_POST[self::NONCE_FIELD]) ? sanitize_text_field(wp_unslash($_POST[self::NONCE_FIELD])) : ''; if (!wp_verify_nonce($nonce, self::NONCE_ACTION)) { $this->redirect('error'); } $code = isset($_POST['akkedli_enrollment_code']) && is_string($_POST['akkedli_enrollment_code']) ? wp_unslash($_POST['akkedli_enrollment_code']) : ''; $notice = self::is_valid_code($code) ? $this->process($code) : 'error'; unset($code); $this->redirect($notice); } public function process($code) { if (!self::is_valid_code($code)) return 'error'; $callback_url = Akkedli_V2_Callback_URL::derive(); if (!is_string($callback_url)) return 'unsupported'; try { Akkedli_V2_Crypto::assert_available(); } catch (Throwable $error) { unset($error); return 'error'; } $owner = Akkedli_Enrollment_Lock::acquire(); if (!is_string($owner)) return 'busy'; $notice = 'error'; try { $status = Akkedli_Connector_State::status(); if (in_array($status, array('v2', 'v2_pending', 'disconnected', 'corrupt'), true)) return 'error'; $restore_on_rejection = 'v2_failed' !== $status; if ('absent' === $status) { $backup = Akkedli_Connector_State::create_legacy_backup(); $expected = array('schema_version' => 1, 'mode' => 'migration_pending', 'legacy_backup' => $backup); if (!Akkedli_Connector_State::replace($expected)) return 'error'; } else { $expected = Akkedli_Connector_State::load(); if (!is_array($expected) || !in_array($expected['mode'], array('migration_pending', 'v2_failed'), true)) return 'error'; $backup = $expected['legacy_backup']; } $result = $this->transport->request($code, $callback_url); if ('definite_rejection' === $result['kind']) { if (!$restore_on_rejection) return 'failed'; return Akkedli_Connector_State::delete_pending() ? 'rejected' : 'pending'; } if ('success' !== $result['kind']) return $restore_on_rejection ? 'pending' : 'failed'; $state = Akkedli_V2_Binding_State::pending($result, $backup, time()); if (!Akkedli_Connector_State::replace($state, $expected)) { return $restore_on_rejection ? 'pending' : 'failed'; } Akkedli_V2_Binding_Poller::schedule_current(); $notice = 'verifying'; } catch (Throwable $error) { unset($error); $notice = in_array(Akkedli_Connector_State::status(), array('migration_pending', 'v2_pending'), true) ? 'pending' : 'error'; } finally { Akkedli_Enrollment_Lock::release($owner); unset($owner, $code, $callback_url, $result, $state); } return $notice; } public static function is_valid_code($code) { if (!is_string($code) || !preg_match('/^[A-Za-z0-9_-]{43}$/D', $code)) return false; try { $decoded = Akkedli_V2_Crypto::base64url_decode($code); } catch (Throwable $error) { unset($error); return false; } return 32 === strlen($decoded); } private function redirect($notice) { $allowed = array('verifying', 'rejected', 'failed', 'pending', 'busy', 'unsupported', 'error'); if (!in_array($notice, $allowed, true)) $notice = 'error'; wp_safe_redirect(add_query_arg(array('page' => 'akkedli-connector', 'akkedli_v2_notice' => $notice), admin_url('admin.php'))); exit; } }