* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace HWI\Bundle\OAuthBundle\OAuth\ResourceOwner; use HWI\Bundle\OAuthBundle\OAuth\Response\PathUserResponse; use HWI\Bundle\OAuthBundle\Security\Core\Authentication\Token\OAuthToken; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\Exception\LazyResponseException; /** * @author zorn-v */ final class TelegramResourceOwner extends GenericOAuth2ResourceOwner { public const TYPE = 'telegram'; protected array $paths = [ 'identifier' => 'id', 'nickname' => 'username', 'realname' => 'first_name', 'firstname' => 'first_name', 'lastname' => 'last_name', 'profilepicture' => 'photo_url', ]; public function getAuthorizationUrl($redirectUri, array $extraParameters = []) { [$botId] = explode(':', $this->options['client_secret']); $parameters = array_merge([ 'bot_id' => $botId, 'origin' => $redirectUri, 'return_to' => $redirectUri, ], $extraParameters); return $this->normalizeUrl($this->options['authorization_url'], $parameters); } public function handles(Request $request) { if (!$request->query->has('code')) { $js = ''; throw new LazyResponseException(new Response($js)); } return true; } public function getAccessToken(Request $request, $redirectUri, array $extraParameters = []) { $token = $request->query->get('code', ''); $token = str_pad(strtr($token, '-_', '+/'), \strlen($token) % 4, '=', \STR_PAD_RIGHT); $authData = json_decode(base64_decode($token), true); if (empty($authData['hash'])) { throw new AuthenticationException('Invalid Telegram auth data'); } if (empty($authData['auth_date']) || (time() - $authData['auth_date']) > 300) { throw new AuthenticationException('Telegram auth data expired'); } $botToken = $this->options['client_secret']; $checkHash = $authData['hash']; unset($authData['hash']); ksort($authData); $dataCheckStr = ''; foreach ($authData as $k => $v) { $dataCheckStr .= sprintf("\n%s=%s", $k, $v); } $dataCheckStr = substr($dataCheckStr, 1); $secretKey = hash('sha256', $botToken, true); $hash = hash_hmac('sha256', $dataCheckStr, $secretKey); if ($hash !== $checkHash) { throw new AuthenticationException('Telegram auth data check failed'); } return ['access_token' => $token]; } public function getUserInformation(array $accessToken, array $extraParameters = []) { $data = base64_decode($accessToken['access_token']); $response = $this->getUserResponse(); $response->setData($data); $response->setResourceOwner($this); $response->setOAuthToken(new OAuthToken($accessToken)); return $response; } protected function configureOptions(OptionsResolver $resolver) { $resolver->setRequired([ 'client_id', 'client_secret', 'authorization_url', ]); $resolver->setDefaults([ 'authorization_url' => 'https://oauth.telegram.org/auth', 'auth_with_one_url' => true, 'state' => null, 'csrf' => false, 'user_response_class' => PathUserResponse::class, ]); } }