$state, 'verifier' => $verifier], self::PENDING_TTL); $url = add_query_arg(array_map('rawurlencode', [ 'site' => PickupSelect_Plugin::shop_origin(), 'return' => admin_url('admin-post.php?action=pickupselect_connect_callback'), 'state' => $state, 'code_challenge' => self::base64url(hash('sha256', $verifier, true)), 'country' => WC()->countries ? WC()->countries->get_base_country() : '', ]), PickupSelect_Plugin::origin() . '/connect/woocommerce'); // a regisztrációs űrlap kitöltéséhez: a #töredéket a böngésző nem küldi el, így nem kerül szerver naplóba $user = wp_get_current_user(); $url .= '#' . http_build_query(['email' => $user->user_email, 'name' => $user->display_name], '', '&', PHP_QUERY_RFC3986); // a PickupSelect oldala külső cím, ezért nem wp_safe_redirect wp_redirect($url); // phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect exit; } // 2–3. lépés: a state ellenőrzése, a kód beváltása a szerverről public static function callback(): void { if (!current_user_can('manage_woocommerce')) { wp_die(esc_html__('You are not allowed to do this.', 'pickupselect'), 403); } $pending = get_transient(self::pending_key()); delete_transient(self::pending_key()); // phpcs:disable WordPress.Security.NonceVerification.Recommended -- a state a nonce szerepét tölti be $state = sanitize_text_field(wp_unslash($_GET['state'] ?? '')); $code = sanitize_text_field(wp_unslash($_GET['code'] ?? '')); $error = sanitize_text_field(wp_unslash($_GET['error'] ?? '')); // phpcs:enable if (!is_array($pending) || $state === '' || !hash_equals($pending['state'], $state)) { self::finish('error', __('The connection request expired or did not start here. Please click Connect again.', 'pickupselect')); } if ($error !== '' || $code === '') { self::finish('warning', __('Connecting to PickupSelect was cancelled.', 'pickupselect')); } $result = self::request('POST', '/api/connect/token', ['code' => $code, 'code_verifier' => $pending['verifier']], false); if (is_wp_error($result)) { self::finish('error', $result->get_error_message()); } update_option(self::TOKEN_OPTION, (string) $result['connection_token'], false); update_option('pickupselect_api_key', (string) $result['api_key']); update_option('pickupselect_widget_key', (string) $result['widget_key']); PickupSelect_Catalog::forget(); // átvett widget is lehet: minden szállító (a szállítók táblázata szűkít), és a bolt országában nyíljon PickupSelect_Widget_Settings::put(); self::finish('success', __('Connected to PickupSelect. Now add a "Pickup point (PickupSelect)" shipping method for each carrier to your shipping zones.', 'pickupselect')); } // a PickupSelect oldalon is megszűnik; a kulcsok maradnak, így a pénztár tovább működik (kézi beállításként) public static function disconnect(): void { self::authorize('pickupselect_disconnect'); if (self::is_connected()) { self::request('DELETE', '/api/manage/connection'); } delete_option(self::TOKEN_OPTION); PickupSelect_Catalog::forget(); self::finish('success', __('Disconnected from PickupSelect. The checkout keeps working with the current keys; their widget can be edited in the PickupSelect dashboard again.', 'pickupselect')); } /** * a PickupSelect szerver hívása (a szerver felőli címen). $authorized: a kapcsolat tokennel. * @return array|WP_Error a válasz JSON-ja; 422-nél a mezők hibái a WP_Error adatában */ public static function request(string $method, string $path, ?array $body = null, bool $authorized = true) { $headers = ['Accept' => 'application/json']; if ($authorized) { $headers['Authorization'] = 'Bearer ' . self::token(); } if ($body !== null) { $headers['Content-Type'] = 'application/json'; } $response = wp_remote_request(PickupSelect_Plugin::server_origin() . $path, [ 'method' => $method, 'timeout' => 15, 'redirection' => 0, 'headers' => $headers, 'body' => $body !== null ? wp_json_encode($body) : null, ]); if (is_wp_error($response)) { /* translators: %s: error message */ return new WP_Error('pickupselect_request', sprintf(__('Could not reach PickupSelect: %s', 'pickupselect'), $response->get_error_message())); } $status = (int) wp_remote_retrieve_response_code($response); $json = json_decode(wp_remote_retrieve_body($response), true); if ($status >= 200 && $status < 300) { return is_array($json) ? $json : []; } // a PickupSelect oldalon lekapcsolták (dashboard): a token már nem jó if ($authorized && $status === 401) { delete_option(self::TOKEN_OPTION); return new WP_Error('pickupselect_revoked', __('This shop was disconnected in the PickupSelect dashboard. Connect again to manage the widget here.', 'pickupselect')); } $message = is_array($json) ? ($json['error'] ?? $json['message'] ?? '') : ''; /* translators: 1: HTTP status code, 2: error message */ return new WP_Error('pickupselect_request', trim(sprintf(__('PickupSelect returned an error (%1$d). %2$s', 'pickupselect'), $status, $message)), [ 'status' => $status, 'errors' => is_array($json) ? ($json['errors'] ?? []) : [], ]); } // egyszeri üzenet a beállítás oldalon (átirányítás után) public static function flash(string $type, string $message): void { set_transient('pickupselect_notice_' . get_current_user_id(), ['type' => $type, 'message' => $message], MINUTE_IN_SECONDS); } public static function show_notice(): void { $notice = get_transient('pickupselect_notice_' . get_current_user_id()); if (!is_array($notice)) { return; } delete_transient('pickupselect_notice_' . get_current_user_id()); printf( '

%2$s

', esc_attr($notice['type']), wp_kses($notice['message'], ['br' => [], 'strong' => []]) ); } private static function finish(string $type, string $message): void { self::flash($type, esc_html($message)); wp_safe_redirect(self::settings_url()); exit; } private static function authorize(string $action): void { if (!current_user_can('manage_woocommerce')) { wp_die(esc_html__('You are not allowed to do this.', 'pickupselect'), 403); } check_admin_referer($action); } private static function pending_key(): string { return 'pickupselect_connect_' . get_current_user_id(); } private static function base64url(string $bytes): string { return rtrim(strtr(base64_encode($bytes), '+/', '-_'), '='); } }