Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
0.00% |
0 / 7 |
CRAP | |
0.00% |
0 / 43 |
OneTapLogin | |
0.00% |
0 / 1 |
|
0.00% |
0 / 7 |
380 | |
0.00% |
0 / 43 |
__construct | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 4 |
|||
name | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
init | |
0.00% |
0 / 1 |
20 | |
0.00% |
0 / 10 |
|||
one_tap_prompt | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
one_tap_scripts | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 6 |
|||
validate_token | |
0.00% |
0 / 1 |
56 | |
0.00% |
0 / 15 |
|||
authenticate | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 5 |
1 | <?php |
2 | /** |
3 | * One Tap Login Class. |
4 | * |
5 | * This class will be responsible for handling |
6 | * Google's one tap login for web functioning. |
7 | * |
8 | * @package RtCamp\GoogleLogin\Modules |
9 | * @since 1.0.16 |
10 | */ |
11 | |
12 | declare(strict_types=1); |
13 | |
14 | namespace RtCamp\GoogleLogin\Modules; |
15 | |
16 | use Exception; |
17 | use RtCamp\GoogleLogin\Utils\Authenticator; |
18 | use RtCamp\GoogleLogin\Utils\GoogleClient; |
19 | use RtCamp\GoogleLogin\Utils\Helper; |
20 | use RtCamp\GoogleLogin\Interfaces\Module; |
21 | use RtCamp\GoogleLogin\Utils\TokenVerifier; |
22 | use function RtCamp\GoogleLogin\plugin; |
23 | |
24 | /** |
25 | * Class OneTapLogin |
26 | * |
27 | * @package RtCamp\GoogleLogin\Modules |
28 | */ |
29 | class OneTapLogin implements Module { |
30 | /** |
31 | * Settings Module. |
32 | * |
33 | * @var Settings |
34 | */ |
35 | private $settings; |
36 | |
37 | /** |
38 | * Token verifier. |
39 | * |
40 | * @var TokenVerifier |
41 | */ |
42 | private $token_verifier; |
43 | |
44 | /** |
45 | * Google client instance. |
46 | * |
47 | * @var GoogleClient |
48 | */ |
49 | private $google_client; |
50 | |
51 | /** |
52 | * Authenticator service. |
53 | * |
54 | * @var Authenticator |
55 | */ |
56 | private $authenticator; |
57 | |
58 | /** |
59 | * OneTapLogin constructor. |
60 | * |
61 | * @param Settings $settings Settings object. |
62 | * @param TokenVerifier $verifier Token verifier object. |
63 | * @param GoogleClient $client Google client instance. |
64 | * @param Authenticator $authenticator Authenticator service instance. |
65 | */ |
66 | public function __construct( Settings $settings, TokenVerifier $verifier, GoogleClient $client, Authenticator $authenticator ) { |
67 | $this->settings = $settings; |
68 | $this->token_verifier = $verifier; |
69 | $this->google_client = $client; |
70 | $this->authenticator = $authenticator; |
71 | } |
72 | |
73 | /** |
74 | * Module name. |
75 | * |
76 | * @return string |
77 | */ |
78 | public function name(): string { |
79 | return 'one_tap_login'; |
80 | } |
81 | |
82 | /** |
83 | * Module Initialization activity. |
84 | * |
85 | * Everything will happen if and only if one tap is active in settings. |
86 | */ |
87 | public function init(): void { |
88 | if ( $this->settings->one_tap_login ) { |
89 | add_action( 'login_enqueue_scripts', [ $this, 'one_tap_scripts' ] ); |
90 | add_action( 'login_footer', [ $this, 'one_tap_prompt' ] ); |
91 | add_action( 'wp_ajax_nopriv_validate_id_token', [ $this, 'validate_token' ] ); |
92 | add_action( 'rtcamp.id_token_verified', [ $this, 'authenticate' ] ); |
93 | add_action( |
94 | 'init', |
95 | function () { |
96 | if ( ! is_user_logged_in() ) { |
97 | $hook_prefix = ( 'sitewide' === $this->settings->one_tap_login_screen ) ? 'wp' : 'login'; |
98 | add_action( $hook_prefix . '_enqueue_scripts', [ $this, 'one_tap_scripts' ] ); |
99 | add_action( $hook_prefix . '_footer', [ $this, 'one_tap_prompt' ], 10000 ); |
100 | } |
101 | } |
102 | ); |
103 | } |
104 | } |
105 | |
106 | /** |
107 | * Show one tap prompt markup. |
108 | * |
109 | * @return void |
110 | */ |
111 | public function one_tap_prompt(): void { ?> |
112 | <div id="g_id_onload" |
113 | data-client_id="<?php echo esc_html( $this->settings->client_id ); ?>" |
114 | data-login_uri="<?php echo esc_html( wp_login_url() ); ?>" |
115 | data-callback="LoginWithGoogleDataCallBack" |
116 | </div> |
117 | <?php |
118 | } |
119 | |
120 | /** |
121 | * Enqueue one-tap related scripts. |
122 | * |
123 | * @return void |
124 | */ |
125 | public function one_tap_scripts(): void { |
126 | $filename = ( defined( 'WP_SCRIPT_DEBUG' ) && true === WP_SCRIPT_DEBUG ) ? 'onetap.min.js' : 'onetap.js'; |
127 | |
128 | wp_enqueue_script( |
129 | 'login-with-google-one-tap', |
130 | 'https://accounts.google.com/gsi/client', |
131 | [], |
132 | filemtime( trailingslashit( plugin()->path ) . 'assets/build/js/onetap.js' ), |
133 | true |
134 | ); |
135 | |
136 | $data = [ |
137 | 'ajaxurl' => admin_url( 'admin-ajax.php' ), |
138 | 'state' => $this->google_client->state(), |
139 | 'homeurl' => get_option( 'home', '' ), |
140 | ]; |
141 | |
142 | wp_register_script( |
143 | 'login-with-google-one-tap-js', |
144 | trailingslashit( plugin()->url ) . 'assets/build/js/' . $filename, |
145 | [ |
146 | 'wp-i18n', |
147 | ], |
148 | filemtime( trailingslashit( plugin()->path ) . 'assets/build/js/onetap.js' ), |
149 | true |
150 | ); |
151 | |
152 | wp_add_inline_script( |
153 | 'login-with-google-one-tap-js', |
154 | 'var TempAccessOneTap=' . json_encode( $data ), //phpcs:disable WordPress.WP.AlternativeFunctions.json_encode_json_encode |
155 | 'before' |
156 | ); |
157 | |
158 | wp_enqueue_script( 'login-with-google-one-tap-js' ); |
159 | } |
160 | |
161 | /** |
162 | * Validate the ID token. |
163 | * |
164 | * @return void |
165 | * @throws Exception Credential verification failure exception. |
166 | */ |
167 | public function validate_token(): void { |
168 | try { |
169 | $token = Helper::filter_input( INPUT_POST, 'token', FILTER_SANITIZE_STRING ); |
170 | $verified = $this->token_verifier->verify_token( $token ); |
171 | |
172 | if ( ! $verified ) { |
173 | throw new Exception( __( 'Cannot verify the credentials', 'login-with-google' ) ); |
174 | } |
175 | |
176 | /** |
177 | * Do something when token has been verified successfully. |
178 | * |
179 | * If we are here that means ID token has been verified. |
180 | * |
181 | * @since 1.0.16 |
182 | */ |
183 | do_action( 'rtcamp.id_token_verified' ); |
184 | |
185 | $redirect_to = apply_filters( 'rtcamp.google_default_redirect', admin_url() ); |
186 | $state = Helper::filter_input( INPUT_POST, 'state', FILTER_SANITIZE_STRING ); |
187 | $decoded_state = $state ? (array) ( json_decode( base64_decode( $state ) ) ) : null; |
188 | |
189 | if ( is_array( $decoded_state ) && ! empty( $decoded_state['provider'] ) && 'google' === $decoded_state['provider'] ) { |
190 | $redirect_to = $decoded_state['redirect_to'] ?? $redirect_to; |
191 | } |
192 | |
193 | wp_send_json_success( |
194 | [ |
195 | 'redirect' => $redirect_to, |
196 | ] |
197 | ); |
198 | die; |
199 | |
200 | } catch ( Exception $e ) { |
201 | wp_send_json_error( $e->getMessage() ); |
202 | } |
203 | } |
204 | |
205 | /** |
206 | * Authenticate the user in WordPress. |
207 | * |
208 | * @return void |
209 | * @throws Exception Authentication exception. |
210 | */ |
211 | public function authenticate(): void { |
212 | $user = $this->token_verifier->current_user(); |
213 | |
214 | if ( is_null( $user ) ) { |
215 | throw new Exception( __( 'User not found to authenticate', 'login-with-google' ) ); |
216 | } |
217 | |
218 | $wp_user = $this->authenticator->authenticate( $user ); |
219 | $this->authenticator->set_auth_cookies( $wp_user ); |
220 | } |
221 | } |