Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 49 |
|
0.00% |
0 / 7 |
CRAP | |
0.00% |
0 / 1 |
OneTapLogin | |
0.00% |
0 / 49 |
|
0.00% |
0 / 7 |
380 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
name | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
init | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
20 | |||
one_tap_prompt | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
one_tap_scripts | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
12 | |||
validate_token | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
56 | |||
authenticate | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 |
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" data-client_id="<?php echo esc_attr( $this->settings->client_id ); ?>" data-login_uri="<?php echo esc_attr( wp_login_url() ); ?>" data-callback="LoginWithGoogleDataCallBack"></div> |
113 | <?php |
114 | } |
115 | |
116 | /** |
117 | * Enqueue one-tap related scripts. |
118 | * |
119 | * @return void |
120 | */ |
121 | public function one_tap_scripts(): void { |
122 | $filename = ( defined( 'WP_SCRIPT_DEBUG' ) && true === WP_SCRIPT_DEBUG ) ? 'onetap.min.js' : 'onetap.js'; |
123 | |
124 | wp_enqueue_script( |
125 | 'login-with-google-one-tap', |
126 | 'https://accounts.google.com/gsi/client', |
127 | [], |
128 | filemtime( trailingslashit( plugin()->path ) . 'assets/build/js/onetap.js' ), |
129 | true |
130 | ); |
131 | |
132 | $data = [ |
133 | 'ajaxurl' => admin_url( 'admin-ajax.php' ), |
134 | 'state' => $this->google_client->state(), |
135 | 'homeurl' => get_option( 'home', '' ), |
136 | ]; |
137 | |
138 | wp_register_script( |
139 | 'login-with-google-one-tap-js', |
140 | trailingslashit( plugin()->url ) . 'assets/build/js/' . $filename, |
141 | [ |
142 | 'wp-i18n', |
143 | ], |
144 | filemtime( trailingslashit( plugin()->path ) . 'assets/build/js/onetap.js' ), |
145 | true |
146 | ); |
147 | |
148 | wp_add_inline_script( |
149 | 'login-with-google-one-tap-js', |
150 | 'var TempAccessOneTap=' . json_encode( $data ), //phpcs:disable WordPress.WP.AlternativeFunctions.json_encode_json_encode |
151 | 'before' |
152 | ); |
153 | |
154 | wp_enqueue_script( 'login-with-google-one-tap-js' ); |
155 | } |
156 | |
157 | /** |
158 | * Validate the ID token. |
159 | * |
160 | * @return void |
161 | * @throws Exception Credential verification failure exception. |
162 | */ |
163 | public function validate_token(): void { |
164 | try { |
165 | $token = Helper::filter_input( INPUT_POST, 'token', FILTER_SANITIZE_STRING ); |
166 | $verified = $this->token_verifier->verify_token( $token ); |
167 | |
168 | if ( ! $verified ) { |
169 | throw new Exception( __( 'Cannot verify the credentials', 'login-with-google' ) ); |
170 | } |
171 | |
172 | /** |
173 | * Do something when token has been verified successfully. |
174 | * |
175 | * If we are here that means ID token has been verified. |
176 | * |
177 | * @since 1.0.16 |
178 | */ |
179 | do_action( 'rtcamp.id_token_verified' ); |
180 | |
181 | $redirect_to = apply_filters( 'rtcamp.google_default_redirect', admin_url() ); |
182 | $state = Helper::filter_input( INPUT_POST, 'state', FILTER_SANITIZE_STRING ); |
183 | $decoded_state = $state ? (array) ( json_decode( base64_decode( $state ) ) ) : null; |
184 | |
185 | if ( is_array( $decoded_state ) && ! empty( $decoded_state['provider'] ) && 'google' === $decoded_state['provider'] ) { |
186 | $redirect_to = $decoded_state['redirect_to'] ?? $redirect_to; |
187 | } |
188 | |
189 | wp_send_json_success( |
190 | [ |
191 | 'redirect' => $redirect_to, |
192 | ] |
193 | ); |
194 | die; |
195 | |
196 | } catch ( Exception $e ) { |
197 | wp_send_json_error( $e->getMessage() ); |
198 | } |
199 | } |
200 | |
201 | /** |
202 | * Authenticate the user in WordPress. |
203 | * |
204 | * @return void |
205 | * @throws Exception Authentication exception. |
206 | */ |
207 | public function authenticate(): void { |
208 | $user = $this->token_verifier->current_user(); |
209 | |
210 | if ( is_null( $user ) ) { |
211 | throw new Exception( __( 'User not found to authenticate', 'login-with-google' ) ); |
212 | } |
213 | |
214 | $wp_user = $this->authenticator->authenticate( $user ); |
215 | $this->authenticator->set_auth_cookies( $wp_user ); |
216 | } |
217 | } |