clientId = $clientId; $this->clientSecret = $clientSecret; } /** * @inheritDoc */ public function login( ?string &$key, ?string &$secret, ?string &$authUrl ): bool { // This state is used to prevent CSRF, i.e., ensuring that authentification request // were initiated on our website. $state = random_int(PHP_INT_MIN, PHP_INT_MAX); $secret = "$state"; $authUrl = $GLOBALS['wgNoteKfetUrl'] . "o/authorize/?" . http_build_query([ 'client_id' => $this->clientId, 'response_type' => 'code', 'scope' => '1_1', 'state' => $secret, ]); return true; } /** * @inheritDoc */ public function logout( UserIdentity &$user ): void { } /** * @inheritDoc */ public function getUser( string $key, string $secret, &$errorMessage ) { if ( !isset( $_GET['code'] ) ) { return false; } if ( !isset( $_GET['state'] ) || empty( $_GET['state'] ) || ( $_GET['state'] !== $secret ) ) { return false; } try { $token = $this->getAccessTokens( $_GET['code'] ); $userInfos = $this->getUserInfos( $token ); return [ 'name' => this->sanitizeName( "$userInfos->normalized_name (note)" ), 'realname' => $userInfos->username, 'email' => $userInfos->email, ]; } catch ( \Exception $e ) { return false; } } private function sanitizeName( string $name ) { // We replace forbidden chars. $res = preg_replace('/[#\/:<>=@\|]/', '-', $name); $res = preg_replace(['/[\[{]/', '/[\]}]/'], ['(', ')'], $res); $res = str_replace('_', ' ', $res); // We remove the last controls chars possibly remaining. return preg_replace('/[^a-zA-Z0-9 !\"$%&\'()*+,\-.;?\\\^`~]/', '', $res); } private function getAccessTokens( string $code ) { $data = [ 'grant_type' => 'authorization_code', 'client_id' => $this->clientId, 'client_secret' => $this->clientSecret, 'code' => $code, ]; $options = [ 'http' => [ 'method' => 'POST', 'header' => 'Content-type: application/x-www-form-urlencoded', 'content' => http_build_query($data), ], ]; $context = stream_context_create($options); $response = file_get_contents($GLOBALS['wgNoteKfetUrl'] . 'o/token/', false, $context); $tokens = json_decode($response); return $tokens->access_token; } private function getUserInfos( string $token ) { $options = [ 'http' => [ 'method' => 'GET', 'header' => "Authorization: Bearer $token", ], ]; $context = stream_context_create($options); $response = file_get_contents($GLOBALS['wgNoteKfetUrl'] . 'api/me/', false, $context); return json_decode($response); } /** * @inheritDoc */ public function saveExtraAttributes( int $id ): void { } }