PluginProbe
Gianism / trunk
Gianism vtrunk
4.3.0 4.3.1 4.3.2 4.3.3 4.3.4 4.4.0 5.0.0 5.0.1 5.0.2 5.1.0 5.2.1 5.2.2 5.3.0 6.0.0 6.0.1 trunk 1.0 1.1 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 All 65 releases
gianism / app / Gianism / Service / Line.php

Line.php in Gianism trunk, at app/Gianism/Service/Line.php

304 lines 8.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Gianism\Service;
3 use Firebase\JWT\JWT;
4 use Firebase\JWT\Key;
5
6 /**
7 * Line class
8 *
9 * @package gianism
10 * @since 3.2.0
11 *
12 * @property string $line_channel_id
13 * @property string $line_channel_secret
14 * @property bool $line_retrieve_email
15 * @property string $line_add_friend_prompt
16 */
17 class Line extends NoMailService {
18
19 public $url_prefix = 'line-auth';
20
21 public $verbose_service_name = 'LINE';
22
23 public $umeta_id = '_wpg_line_id';
24
25 public $umeta_profile_pic = '_wpg_line_pic';
26
27 protected $pseudo_domain = 'pseudo.line.me';
28
29 protected $option_keys = [
30 'line_enabled' => false,
31 'line_channel_id' => '',
32 'line_channel_secret' => '',
33 'line_retrieve_email' => false,
34 'line_add_friend_prompt' => '',
35 ];
36
37
38 /**
39 * Constructor
40 *
41 * @param array $argument
42 */
43 protected function __construct( array $argument = [] ) {
44 parent::__construct( $argument );
45 // Filter rewrite name
46 add_filter(
47 'gianism_filter_service_prefix',
48 function ( $prefix ) {
49 if ( 'line-auth' === $prefix ) {
50 $prefix = 'line';
51 }
52 return $prefix;
53 }
54 );
55 }
56
57 /**
58 * Returns API endpoint
59 *
60 * @param string $action
61 *
62 * @return false|string
63 * @throws \Exception
64 */
65 protected function get_api_url( $action ) {
66 switch ( $action ) {
67 case 'connect':
68 case 'login':
69 $auth_url = 'https://access.line.me/oauth2/v2.1/authorize';
70 if ( function_exists( 'random_int' ) ) {
71 $state = sha1( random_bytes( 24 ) );
72 } else {
73 $state = sha1( uniqid() );
74 }
75 $this->session->write( 'line_state', $state );
76 $params = [
77 'response_type' => 'code',
78 'client_id' => $this->line_channel_id,
79 'redirect_uri' => home_url( "/{$this->url_prefix}/" ),
80 'scope' => rawurlencode( 'profile openid email' ),
81 'state' => $state,
82 // 'prompt' => 'consent', // For Debug by displaying consent screen always.
83 ];
84 $prompt = $this->line_add_friend_prompt;
85 if ( $prompt ) {
86 $params['bot_prompt'] = $prompt;
87 }
88 /**
89 * giansim_line_auth_params
90 *
91 * @param array $args Query parameters
92 * @param string $context login or connect.
93 */
94 $args = apply_filters( 'gianism_line_auth_params', $params, $action );
95 return add_query_arg( $args, $auth_url );
96 default:
97 return false;
98 break;
99 }
100 }
101
102 /**
103 * Check if user has line account.
104 *
105 * @param int $user_id
106 *
107 * @return bool
108 */
109 public function is_connected( $user_id ) {
110 return (bool) get_user_meta( $user_id, $this->umeta_id, true );
111 }
112
113
114 /**
115 * @param int $user_id
116 *
117 * @return void
118 */
119 public function disconnect( $user_id ) {
120 delete_user_meta( $user_id, $this->umeta_id );
121 delete_user_meta( $user_id, $this->umeta_profile_pic );
122 }
123
124 /**
125 * Parse request.
126 *
127 * @return \stdClass
128 * @throws \Exception
129 */
130 protected function validate_callback() {
131 $code = $this->input->request( 'code' );
132 $state = $this->input->request( 'state' );
133 $saved = $this->session->get( 'line_state' );
134 $error = $this->input->request( 'error' );
135 $msg = $this->input->request( 'error_description' );
136 if ( $error || $msg ) {
137 throw new \Exception( $msg, 500 );
138 }
139 if ( $state !== $saved ) {
140 throw new \Exception( __( 'Sorry, but wrong access. Please try again.', 'wpg-gianism' ), 500 );
141 }
142 $data = [
143 'grant_type' => 'authorization_code',
144 'code' => $code,
145 'redirect_uri' => home_url( "/{$this->url_prefix}/" ),
146 'client_id' => $this->line_channel_id,
147 'client_secret' => $this->line_channel_secret,
148 ];
149 $result = wp_remote_post(
150 'https://api.line.me/oauth2/v2.1/token',
151 [
152 'body' => $data,
153 ]
154 );
155 if ( is_wp_error( $result ) ) {
156 throw new \Exception( $result->get_error_message(), 500 );
157 }
158 $json = json_decode( $result['body'] );
159 if ( ! $json || ! isset( $json->id_token ) ) {
160 throw new \Exception( __( 'Sorry, but failed to parse request.', 'wp-gianism' ), 500 );
161 }
162 JWT::$leeway = 5;
163 $jwt = JWT::decode( $json->id_token, new Key( $this->line_channel_secret, 'HS256' ) );
164 $json->id_token = $jwt;
165 return $json;
166 }
167
168 /**
169 * Create pseudo email
170 *
171 * @param \stdClass$prefix
172 *
173 * @return string
174 */
175 protected function create_pseudo_email( $prefix ) {
176 if ( isset( $prefix->email ) && $prefix->email ) {
177 return $prefix->email;
178 } else {
179 return parent::create_pseudo_email( $prefix->sub ); // TODO: Change the autogenerated stub
180 }
181 }
182
183 /**
184 *
185 *
186 * @param string $context
187 *
188 * @return bool
189 */
190 public function need_confirmation( $context = 'login' ) {
191 return (bool) $this->line_retrieve_email;
192 }
193
194 /**
195 * Handle actions.
196 *
197 * @param string $action
198 */
199 public function handle_default( $action ) {
200 $redirect_url = $this->session->get( 'redirect_to' );
201 switch ( $action ) {
202 case 'login':
203 try {
204 $response = $this->validate_callback();
205 $id_token = $response->id_token;
206
207 $line_id = $id_token->sub;
208 $user_id = $this->get_meta_owner( $this->umeta_id, $line_id );
209 if ( ! $user_id ) {
210 $this->test_user_can_register();
211 $email = $this->create_pseudo_email( $id_token );
212 if ( email_exists( $email ) ) {
213 throw new \Exception( $this->duplicate_account_string() );
214 }
215 $user_name = 'line-' . $line_id;
216 /**
217 * @see Facebook
218 */
219 $user_name = apply_filters( 'gianism_register_name', $user_name, $this->service, $response );
220 $user_id = wp_create_user( $user_name, wp_generate_password(), $email );
221 if ( is_wp_error( $user_id ) ) {
222 throw new \Exception( $this->registration_error_string() );
223 }
224 // Update user meta
225 update_user_meta( $user_id, $this->umeta_id, $line_id );
226 if ( ! empty( $response->id_token->picture ) ) {
227 update_user_meta( $user_id, $this->umeta_profile_pic, $response->id_token->picture );
228 }
229 $profile_name = sanitize_text_field( $response->id_token->name );
230 update_user_meta( $user_id, 'nickname', $profile_name );
231 $this->db->update(
232 $this->db->users,
233 array(
234 'display_name' => $profile_name,
235 ),
236 array(
237 'ID' => $user_id,
238 ),
239 array( '%s' ),
240 array( '%d' )
241 );
242 $this->user_password_unknown( $user_id );
243 $this->hook_connect( $user_id, $response, true );
244 $this->welcome( $profile_name );
245 }
246 // Make user logged in
247 $this->set_auth_cookie( $user_id );
248 $redirect_url = $this->filter_redirect( $redirect_url, 'login' );
249 } catch ( \Exception $e ) {
250 $this->auth_fail( $e->getMessage() );
251 $redirect_url = wp_login_url( $redirect_url, true );
252 $redirect_url = $this->filter_redirect( $redirect_url, 'login-failure' );
253 }
254 wp_redirect( $redirect_url );
255 exit;
256 break;
257 case 'connect':
258 try {
259 $response = $this->validate_callback();
260 $line_id = $response->id_token->sub;
261 if ( $this->get_meta_owner( $this->umeta_id, $line_id ) ) {
262 throw new \Exception( $this->duplicate_account_string() );
263 }
264 update_user_meta( get_current_user_id(), $this->umeta_id, $line_id );
265 // Fires hook
266 $this->hook_connect( get_current_user_id(), $response );
267 // Save message
268 $this->welcome( $response->id_token->name );
269 // Apply filter
270 $redirect_url = $this->filter_redirect( $redirect_url, 'connect' );
271 } catch ( \Exception $e ) {
272 $this->auth_fail( $e->getMessage() );
273 $redirect_url = $this->filter_redirect( $redirect_url, 'connect-failure' );
274 }
275 // Connection finished. Let's redirect.
276 if ( ! $redirect_url ) {
277 $redirect_url = admin_url( 'profile.php' );
278 }
279 wp_redirect( $redirect_url );
280 exit;
281 break;
282 default:
283 /**
284 * @see Facebook
285 */
286 do_action(
287 'gianism_extra_action',
288 $this->service_name,
289 $action,
290 [
291 'redirect_to' => $redirect_url,
292 ]
293 );
294 // translators: %1$s is URL, %2$s is a site name.
295 $this->input->wp_die( sprintf( __( 'Sorry, but wrong access. Please go back to <a href="%1$s">%2$s</a>.', 'wp-gianism' ), esc_url( home_url( '/' ) ), get_bloginfo( 'name' ) ), 500, false );
296 break;
297 }
298 }
299
300 public function svg_path() {
301 return 'line.png';
302 }
303 }
304