PluginProbe
ووسلام – همگام سازی ووکامرس و باسلام / 1.10.18
ووسلام – همگام سازی ووکامرس و باسلام v1.10.18
1.10.18 1.10.17 1.10.15 1.10.14 1.10.13 1.10.12 1.10.10 1.10.9 1.10.8 1.10.7 1.10.6 1.10.5 1.10.4 1.10.3 1.10.2 1.10.1 1.10.0 1.9.2 1.9.1 1.9.0 1.8.8 1.8.5 1.8.6 1.8.7 1.8.4 All 51 releases
sync-basalam / includes / Admin / Settings / OAuthManager.php

OAuthManager.php in ووسلام – همگام سازی ووکامرس و باسلام 1.10.18, at includes/Admin/Settings/OAuthManager.php

145 lines 5.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace SyncBasalam\Admin\Settings;
4
5 use SyncBasalam\Config\Endpoints;
6 use SyncBasalam\Services\ApiServiceManager;
7
8 defined('ABSPATH') || exit;
9
10 class OAuthManager
11 {
12 /** Prefix for the per-user transient holding a pending OAuth authorization. */
13 const OAUTH_STATE_TRANSIENT = 'sync_basalam_oauth_state_';
14
15 /** Lifetime of a pending OAuth authorization — the SSO round-trip window. */
16 const OAUTH_STATE_TTL = 600; // 10 * MINUTE_IN_SECONDS
17
18 /**
19 * Remember that the current admin has just started an OAuth authorization.
20 *
21 * This is called only from the nonce-protected initiation flow, so the
22 * marker it stores cannot be planted by a forged cross-site request. The
23 * callback later requires (and consumes) this marker, which is what turns
24 * the token-saving callback from "always forgeable" into "only valid for a
25 * flow this admin actually started".
26 */
27 public static function issueOauthState()
28 {
29 $state = wp_generate_password(64, false);
30 set_transient(self::OAUTH_STATE_TRANSIENT . get_current_user_id(), $state, self::OAUTH_STATE_TTL);
31
32 return $state;
33 }
34
35 /**
36 * Validate and consume the pending OAuth authorization for the current user.
37 *
38 * Single use: the marker is deleted whether or not it was present, so a
39 * replayed or forged callback cannot reuse it.
40 */
41 private static function verifyOauthState()
42 {
43 $key = self::OAUTH_STATE_TRANSIENT . get_current_user_id();
44 $expected = get_transient($key);
45 delete_transient($key);
46
47 // The token exchange is routed back through the Hamsalam proxy, which
48 // consumes the SSO "state" (the site URL) and does not forward a secret
49 // we control. The single-use marker set during the authenticated
50 // initiation is therefore the value that authorises the write.
51 return ! empty($expected);
52 }
53
54 public function getOauthData()
55 {
56 $oauthDataUrl = apply_filters('sync_basalam_oauth_data_url', Endpoints::HAMSALAM_OAUTH_DATA);
57 $defaultClientId = apply_filters('sync_basalam_oauth_default_client_id', 779);
58 $defaultRedirectUri = apply_filters('sync_basalam_oauth_default_redirect_uri', Endpoints::HAMSALAM_OAUTH_TOKEN);
59
60 try {
61 $apiservice = syncBasalamContainer()->get(ApiServiceManager::class);
62 $request = $apiservice->get($oauthDataUrl);
63 $clientId = $request['body']['client_id'] ?? $defaultClientId;
64 $redirectUri = $request['body']['redirect_uri'] ?? $defaultRedirectUri;
65 } catch (\Throwable $th) {
66 $clientId = $defaultClientId;
67 $redirectUri = $defaultRedirectUri;
68 }
69
70 return [
71 'client_id' => $clientId,
72 'redirect_uri' => $redirectUri,
73 ];
74 }
75
76 public static function saveOauthData()
77 {
78 // CSRF protection: this callback performs a state-changing write from a
79 // plain GET, so it must be tied to an OAuth flow the current admin
80 // actually initiated. Without this an attacker could lure a logged-in
81 // admin to the callback URL and overwrite the stored Basalam credentials.
82 if (! current_user_can('manage_options') || ! self::verifyOauthState()) {
83 wp_die(
84 esc_html__('درخواست نا�
85 عتبر است.', 'sync-basalam'),
86 esc_html__('خطای ا�
87 نیتی', 'sync-basalam'),
88 ['response' => 403]
89 );
90 }
91
92 $isVendor = isset($_GET['is_vendor']) ? sanitize_text_field(wp_unslash($_GET['is_vendor'])) : true;
93 $vendorId = isset($_GET['vendor_id']) ? sanitize_text_field(intval($_GET['vendor_id'])) : null;
94 $hamsalamToken = isset($_GET['hamsalam_token']) ? sanitize_text_field(wp_unslash($_GET['hamsalam_token'])) : null;
95 $hamsalamBusinessId = isset($_GET['hamsalam_business_id']) ? sanitize_text_field(wp_unslash($_GET['hamsalam_business_id'])) : null;
96 $accessToken = isset($_GET['access_token']) ? sanitize_text_field(wp_unslash($_GET['access_token'])) : null;
97 $refreshToken = isset($_GET['refresh_token']) ? sanitize_text_field(wp_unslash($_GET['refresh_token'])) : null;
98 $expiresIn = isset($_GET['expires_in']) ? sanitize_text_field(intval($_GET['expires_in'])) : null;
99
100 // Allow pro version to handle custom fields
101 $extraData = apply_filters('sync_basalam_oauth_save_extra_data', []);
102
103 if ($isVendor == 'false') {
104 $data = [SettingsConfig::IS_VENDOR => false];
105 $data = apply_filters('sync_basalam_oauth_non_vendor_data', $data, $vendorId, $accessToken, $refreshToken, $extraData);
106 SettingsManager::updateSettings($data);
107 return true;
108 }
109
110 $data = [
111 SettingsConfig::VENDOR_ID => $vendorId,
112 SettingsConfig::IS_VENDOR => $isVendor,
113 SettingsConfig::TOKEN => $accessToken,
114 SettingsConfig::REFRESH_TOKEN => $refreshToken,
115 SettingsConfig::HAMSALAM_TOKEN => $hamsalamToken,
116 SettingsConfig::HAMSALAM_BUSINESS_ID => $hamsalamBusinessId,
117 SettingsConfig::EXPIRE_TOKEN_TIME => $expiresIn,
118 ];
119
120 $data = array_merge($data, $extraData);
121
122 SettingsManager::updateSettings($data);
123
124 return true;
125 }
126
127 public function getOAuthUrls()
128 {
129 $oauthData = $this->getOauthData();
130 $siteUrl = get_site_url();
131
132 $scopes = apply_filters('sync_basalam_oauth_scopes', "vendor.product.write vendor.parcel.write customer.profile.read vendor.profile.read vendor.parcel.read vendor.profile.write customer.chat.read customer.chat.write customer.identity.read");
133
134 return [
135 'redirect_uri' => $oauthData['redirect_uri'],
136 'url_req_token' => Endpoints::oauthLoginUrl(
137 $oauthData['client_id'],
138 $scopes,
139 $oauthData['redirect_uri'],
140 $siteUrl
141 ),
142 ];
143 }
144 }
145