PluginProbe
Timetics – Appointment Booking Calendar & Scheduling / 1.0.61
Timetics – Appointment Booking Calendar & Scheduling v1.0.61
1.0.61 1.0.60 1.0.59 1.0.58 1.0.57 1.0.56 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.15 1.0.16 1.0.17 1.0.18 1.0.19 1.0.2 1.0.20 1.0.21 1.0.22 1.0.23 1.0.24 All 62 releases
timetics / core / integrations / google / client.php

client.php in Timetics – Appointment Booking Calendar & Scheduling 1.0.61, at core/integrations/google/client.php

277 lines 7.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Google Calendar Auth Class
4 *
5 * @package Timetics
6 */
7 namespace Timetics\Core\Integrations\Google;
8
9 use Exception;
10 use InvalidArgumentException;
11
12 /**
13 * Class Auth
14 */
15 class Client {
16 const TIMETICS_REVOKE_URI = 'https://oauth2.googleapis.com/revoke';
17 const TIMETICS_TOKEN_URI = 'https://oauth2.googleapis.com/token';
18 const TIMETICS_AUTH_URL = 'https://accounts.google.com/o/oauth2/v2/auth';
19 const API_BASE_PATH = 'https://www.googleapis.com';
20
21 /**
22 * Store google app client id
23 *
24 * @var string
25 */
26 private $client_id;
27
28 /**
29 * Store google app secrete
30 *
31 * @var string
32 */
33 private $client_secrete;
34
35 /**
36 * Store google app auth scope
37 *
38 * @var string
39 */
40 private $auth_scope;
41
42 /**
43 * Store google auth redirect uri
44 *
45 * @var string
46 */
47 private $redirect_uri;
48
49 /**
50 * Get app client id
51 *
52 * @return string
53 */
54 public function get_client_id() {
55 return $this->client_id;
56 }
57
58 /**
59 * Get app secrete
60 *
61 * @return string
62 */
63 public function get_client_secrete() {
64 return $this->client_secrete;
65 }
66
67 /**
68 * Get app auth scope
69 *
70 * @return string
71 */
72 public function get_auth_scope() {
73 return $this->auth_scope;
74 }
75
76 /**
77 * Get auth redirect uri
78 *
79 * @return string
80 */
81 public function get_redirect_uri() {
82 return $this->redirect_uri;
83 }
84
85 /**
86 * Get auth url
87 *
88 * @return string
89 */
90 public function get_auth_url( $state = '' ) {
91 $params = array(
92 'client_id' => $this->client_id,
93 'scope' => urlencode_deep( $this->auth_scope ),
94 'redirect_uri' => $this->redirect_uri,
95 'response_type' => 'code',
96 'access_type' => 'offline',
97 'prompt' => 'consent',
98 );
99
100 if ( ! empty( $state ) ) {
101 $params['state'] = $state;
102 }
103
104 return add_query_arg( $params, self::TIMETICS_AUTH_URL );
105 }
106
107 /**
108 * Set google authentication configuration
109 *
110 * @return void
111 */
112 public function set_auth_config( $args = array() ) {
113 $defaults = array(
114 'client_id' => '',
115 'client_secrete' => '',
116 );
117
118 $args = wp_parse_args( $args, $defaults );
119
120 $this->client_id = $args['client_id'];
121 $this->client_secrete = $args['client_secrete'];
122 }
123
124 /**
125 * Set authentication scope
126 *
127 * @return void
128 */
129 public function add_scope( $scope ) {
130 $this->auth_scope = $scope;
131 }
132
133 /**
134 * Set redirect uri
135 *
136 * @param string $uri Redirect uri
137 *
138 * @return void
139 */
140 public function set_redirect_uri( $uri ) {
141 $this->redirect_uri = $uri;
142 }
143
144 /**
145 * Fetch access token
146 *
147 * @param string $code
148 *
149 * @return array Token data on success.
150 * @throws \InvalidArgumentException When the code is empty.
151 * @throws \Exception On transport failure or a non-200 token response.
152 */
153 public function fetch_access_token_with_auth_code( $code ) {
154 if ( strlen( $code ) === 0 ) {
155 throw new InvalidArgumentException( 'Invalid code' );
156 }
157
158 $args = array(
159 'client_id' => $this->client_id,
160 'client_secret' => $this->client_secrete,
161 'code' => $code,
162 'redirect_uri' => $this->redirect_uri,
163 'grant_type' => 'authorization_code',
164 );
165
166 $response = wp_remote_post( self::TIMETICS_TOKEN_URI, array( 'body' => $args ) );
167
168 if ( is_wp_error( $response ) ) {
169 throw new Exception( $response->get_error_message() );
170 }
171
172 $status_code = (int) wp_remote_retrieve_response_code( $response );
173 $body = wp_remote_retrieve_body( $response );
174 $data = json_decode( $body, true );
175
176 if ( 200 !== $status_code || empty( $data['access_token'] ) ) {
177 $message = ! empty( $data['error_description'] ) ? $data['error_description'] : __( 'Failed to obtain Google access token.', 'timetics' );
178 throw new Exception( $message );
179 }
180
181 return $data;
182 }
183
184 /**
185 * Fetch access token by using refresh token
186 *
187 * @param string $refresh_token
188 *
189 * @return array|\WP_Error Token data on success, or a WP_Error whose error_data carries a boolean `transient` flag.
190 */
191 public function fetch_access_token_with_refresh_token( $refresh_token ) {
192 if ( empty( $refresh_token ) ) {
193 return new \WP_Error(
194 'timetics_google_no_refresh_token',
195 'No Google refresh token is available for this account.',
196 array( 'transient' => false )
197 );
198 }
199
200 $args = array(
201 'client_id' => $this->client_id,
202 'client_secret' => $this->client_secrete,
203 'refresh_token' => $refresh_token,
204 'redirect_uri' => $this->redirect_uri,
205 'grant_type' => 'refresh_token',
206 );
207
208 $response = wp_remote_post( self::TIMETICS_TOKEN_URI, array( 'body' => $args ) );
209
210 // Transport-level failure (DNS, timeout, connection refused). Transient:
211 // the credential is fine, Google was just briefly unreachable.
212 if ( is_wp_error( $response ) ) {
213 return new \WP_Error(
214 'timetics_google_refresh_http_error',
215 $response->get_error_message(),
216 array( 'transient' => true )
217 );
218 }
219
220 $status_code = (int) wp_remote_retrieve_response_code( $response );
221 $body = wp_remote_retrieve_body( $response );
222 $data = json_decode( $body, true );
223
224 if ( 200 === $status_code && ! empty( $data['access_token'] ) ) {
225 return $data;
226 }
227
228 $google_error = isset( $data['error'] ) ? $data['error'] : '';
229 $transient = ( 'invalid_grant' !== $google_error );
230
231 if ( 429 === $status_code || $status_code >= 500 || 0 === $status_code ) {
232 $transient = true;
233 }
234
235 if ( defined( 'WP_DEBUG' ) && WP_DEBUG && defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) {
236 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug logging is guarded by WP_DEBUG checks.
237 error_log( sprintf( 'Timetics Google token refresh failed (HTTP %d): %s', $status_code, $body ) );
238 }
239
240 return new \WP_Error(
241 'timetics_google_refresh_failed',
242 ! empty( $data['error_description'] ) ? $data['error_description'] : 'Failed to refresh Google access token.',
243 [
244 'transient' => $transient,
245 'status_code' => $status_code,
246 'error' => $google_error,
247 ]
248 );
249 }
250
251 /**
252 * Revoke authorization
253 *
254 * @param string $token
255 *
256 * @return bool
257 */
258 public function revoke( $token ) {
259 $response = wp_remote_post(
260 self::TIMETICS_REVOKE_URI, array(
261 'headers' => array(
262 'content-type' => 'application/x-www-form-urlencoded',
263 ),
264 'body' => build_query(
265 array(
266 'token' => $token,
267 )
268 ),
269 )
270 );
271
272 $status_code = wp_remote_retrieve_response_code( $response );
273
274 return $status_code === 200;
275 }
276 }
277