AnonSec Shell
Server IP : 85.193.89.191  /  Your IP : 3.133.143.36
Web Server : Apache
System : Linux 956367-cx40159.tmweb.ru 3.10.0-1160.105.1.el7.x86_64 #1 SMP Thu Dec 7 15:39:45 UTC 2023 x86_64
User : bitrix ( 600)
PHP Version : 8.1.27
Disable Function : NONE
MySQL : OFF  |  cURL : OFF  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : ON  |  Pkexec : ON
Directory :  /home/bitrix/www/bitrix/modules/mail/lib/helper/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ HOME ]     

Current File : /home/bitrix/www/bitrix/modules/mail/lib/helper/oauth.php
<?php

namespace Bitrix\Mail\Helper;

use Bitrix\Main;
use Bitrix\Mail;
use Bitrix\Main\Web\Uri;
use Bitrix\Mail\Helper\OAuth\UserData;


abstract class OAuth
{

	/**
	 * @var \CSocServOAuthTransport
	 */
	protected $oauthEntity;

	protected $service, $storedUid;

	public const WEB_TYPE = 'web';
	public const MOBILE_TYPE = 'mobile';
	protected UserData $publicUserData;

	/**
	 * Returns the list of supported services
	 *
	 * @return array
	 */
	public static function getKnownServices()
	{
		static $knownServices;

		if (is_null($knownServices))
		{
			$knownServices = [
				OAuth\Google::getServiceName(),
				OAuth\LiveId::getServiceName(),
				OAuth\Yandex::getServiceName(),
				OAuth\Mailru::getServiceName(),
				OAuth\Office365::getServiceName(),
			];
		}

		return $knownServices;
	}

	/**
	 * Returns helper instance
	 *
	 * @param string $service Service name.
	 * @return \Bitrix\Mail\Helper\OAuth|false
	 */
	public static function getInstance($service = null): bool|OAuth
	{
		if (get_called_class() != get_class())
		{
			$className = get_called_class();
			$service = $className::getServiceName();
		}
		else
		{
			if (!in_array($service, self::getKnownServices()))
			{
				return false;
			}

			$className = sprintf('%s\OAuth\%s', __NAMESPACE__, $service);
		}

		if (!Main\Loader::includeModule('socialservices'))
		{
			return false;
		}

		$instance = new $className;

		$instance->service = $service;
		$instance->storedUid = sprintf('%x%x', time(), rand(0, 0xffffffff));

		if (!$instance->check())
		{
			return false;
		}

		return $instance;
	}

	/**
	 * Returns helper instance by packed metadata
	 *
	 * @param string $meta Packed metadata.
	 * @return \Bitrix\Mail\Helper\OAuth|false
	 */
	public static function getInstanceByMeta($meta)
	{
		if ($meta = static::parseMeta($meta))
		{
			if ($instance = self::getInstance($meta['service']))
			{
				if ('oauthb' == $meta['type'])
				{
					$instance->storedUid = $meta['key'];
				}

				return $instance;
			}
		}
	}

	/**
	 * Returns packed metadata for instance
	 *
	 * @return string
	 * @throws Main\ObjectException
	 */
	public function buildMeta()
	{
		return sprintf(
			"\x00oauthb\x00%s\x00%s",
			$this->getServiceName(),
			$this->getStoredUid()
		);
	}

	/**
	 * Returns unpacked metadata
	 *
	 * @param string $meta Packed metadata.
	 * @return array
	 */
	public static function parseMeta($meta)
	{
		$regex = sprintf(
			'/^\x00(oauthb)\x00(%s)\x00([a-f0-9]+)$/',
			join(
				'|',
				array_map(
					function ($item)
					{
						return preg_quote($item, '/');
					},
					self::getKnownServices()
				)
			)
		);

		if (!preg_match($regex, $meta, $matches))
		{
			if (!preg_match('/^\x00(oauth)\x00(google|liveid)\x00(\d+)$/', $meta, $matches))
			{
				return null;
			}
		}

		return array(
			'type' => $matches[1],
			'service' => $matches[2],
			'key' => $matches[3],
		);
	}

	/**
	 * Returns token from socialservices
	 *
	 * @param string $service Service name.
	 * @param string $key User ID.
	 * @return string|null
	 */
	private static function getSocservToken($service, $key)
	{
		if (Main\Loader::includeModule('socialservices'))
		{
			switch ($service)
			{
				case 'google':
					$oauthClient = new \CSocServGoogleOAuth($key);
					$oauthClient->getEntityOAuth()->addScope('https://mail.google.com/');
					break;
				case 'liveid':
					$oauthClient = new \CSocServLiveIDOAuth($key);
					$oauthClient->getEntityOAuth()->addScope(['wl.imap', 'wl.offline_access']);
					break;
			}

			if (!empty($oauthClient))
			{
				return $oauthClient->getStorageToken() ?: false;
			}
		}

		return null;
	}

	/**
	 * Returns token by packed metadata
	 *
	 * @param string $meta Packed metadata.
	 * @param int $expireGapSeconds Gap needed for using token, to ensure when we use token it still alive
	 *
	 * @return string|null
	 */
	public static function getTokenByMeta($meta, int $expireGapSeconds = 10)
	{
		if ($meta = static::parseMeta($meta))
		{
			if ('oauthb' == $meta['type'])
			{
				if ($oauthHelper = self::getInstance($meta['service']))
				{
					return $oauthHelper->getStoredToken($meta['key'], $expireGapSeconds) ?: false;
				}
			}
			else if ('oauth' == $meta['type'])
			{
				return self::getSocservToken($meta['service'], $meta['key']);
			}
		}
	}

	/**
	 * Returns user data by packed metadata
	 *
	 * @param string $meta Packed metadata.
	 * @param boolean $secure Strip raw data (includes tokens).
	 * @return array|null
	 */
	public static function getUserDataByMeta($meta, $secure = true)
	{
		if ($meta = static::parseMeta($meta))
		{
			if ($oauthHelper = self::getInstance($meta['service']))
			{
				if ('oauthb' == $meta['type'])
				{
					$oauthHelper->getStoredToken($meta['key']);
				}
				else if ('oauth' == $meta['type'])
				{
					if ($token = self::getSocservToken($meta['service'], $meta['key']))
					{
						$oauthHelper->getOAuthEntity()->setToken($token);
					}
				}

				return $oauthHelper->getUserData($secure);
			}
		}

		return null;
	}

	/**
	 * Returns service interface entity
	 *
	 * @return mixed
	 */
	public function getOAuthEntity()
	{
		return $this->oauthEntity;
	}

	/**
	 * Returns instance UID
	 *
	 * @return string
	 */
	public function getStoredUid()
	{
		return $this->storedUid;
	}

	/**
	 * Returns server OAuth handler URI
	 *
	 * @param boolean $final Skip Bitrix24 proxy.
	 * @return string
	 */
	public function getRedirect(bool $final = true): string
	{
		if (isModuleInstalled('bitrix24') && defined('BX24_HOST_NAME') && !$final)
		{
			return $this->getControllerUrl() . '/redirect.php';
		}
		else
		{
			$uri = new Uri(Main\Engine\UrlManager::getInstance()->getHostUrl().'/bitrix/tools/mail_oauth.php');
			return $uri->getLocator();
		}
	}

	/**
	 * Returns service OAuth endpoint URI
	 *
	 * @return string
	 */
	public function getUrl(): string
	{
		global $APPLICATION;

		if (isModuleInstalled('bitrix24') && defined('BX24_HOST_NAME'))
		{
			$state = sprintf(
				'%s?%s',
				$this->getRedirect(),
				http_build_query(array(
					'check_key' => \CSocServAuthManager::getUniqueKey(),
					'dummy' => 'https://dummy.bitrix24.com/',
					'state' => rawurlencode(http_build_query(array(
						'service' => $this->service,
						'uid' => $this->storedUid,
					))),
				))
			);
		}
		else
		{
			$state = http_build_query(array(
				'check_key' => \CSocServAuthManager::getUniqueKey(),
				'service' => $this->service,
				'uid' => $this->storedUid,
			));
		}

		return $this->oauthEntity->getAuthUrl($this->getRedirect(false), $state);
	}

	/**
	 * Fetches token by instance UID from DB
	 *
	 * @return array|false
	 */
	protected function fetchStoredToken()
	{
		return Mail\Internals\OAuthTable::getList(array(
			'filter' => array(
				'=UID' => $this->storedUid,
			),
			'order' => array(
				'ID' => 'DESC',
			),
		))->fetch();
	}

	/**
	 * Returns token by instance UID
	 *
	 * @param string $uid Instance UID.
	 * @param int $expireGapSeconds Gap needed for using token, to ensure when we use token it still alive
	 *
	 * @return string|null
	 */
	public function getStoredToken($uid = null, int $expireGapSeconds = 10)
	{
		$token = null;

		if (!empty($uid))
		{
			$this->storedUid = $uid;
		}

		$item = $this->fetchStoredToken();

		if (!empty($item))
		{
			$this->oauthEntity->setToken($token = $item['TOKEN']);
			$this->oauthEntity->setRefreshToken($item['REFRESH_TOKEN']);
			$expireThreshold = time() + $expireGapSeconds;

			if (empty($token) || $item['TOKEN_EXPIRES'] > 0 && $item['TOKEN_EXPIRES'] < $expireThreshold)
			{
				$this->oauthEntity->setToken(null);

				if (!empty($item['REFRESH_TOKEN']))
				{
					if ($this->oauthEntity->getNewAccessToken($item['REFRESH_TOKEN']))
					{
						$tokenData = $this->oauthEntity->getTokenData();

						Mail\Internals\OAuthTable::update(
							$item['ID'],
							array(
								'TOKEN' => $tokenData['access_token'],
								'REFRESH_TOKEN' => $tokenData['refresh_token'],
								'TOKEN_EXPIRES' => $tokenData['expires_in'],
							)
						);
					}
				}

				$token = $this->oauthEntity->getToken();
			}
		}

		return $token;
	}

	/**
	 * Obtains tokens from service
	 *
	 * @param string $code Service authorization code.
	 * @return boolean
	 */
	public function getAccessToken($code = null)
	{
		if ($code)
		{
			$this->oauthEntity->setCode($code);
		}

		$oauthData = $_SESSION['OAUTH_DATA'];

		$result = $this->oauthEntity->getAccessToken($this->getRedirect(false));

		$_SESSION['OAUTH_DATA'] = $oauthData;

		return $result;
	}

	/**
	 * Returns user data
	 *
	 * @param boolean $secure Strip raw data (includes tokens).
	 * @return array|null
	 */
	public function getUserData($secure = true)
	{
		try
		{
			$userData = $this->oauthEntity->getCurrentUser();
		}
		catch (Main\SystemException $e)
		{
		}

		if (!empty($userData))
		{
			return array_merge(
				$this->mapUserData($userData),
				$secure ? array() : array('__data' => $userData)
			);
		}
	}

	/**
	 * Returns unified user data
	 *
	 * @param array $userData User data.
	 * @return array
	 */
	abstract protected function mapUserData(array $userData);

	/**
	 * Returns service name
	 *
	 * @throws \Bitrix\Main\ObjectException
	 * @return string
	 */
	public static function getServiceName()
	{
		throw new Main\ObjectException('abstract');
	}

    public function saveResponse($state): bool
	{
		$this->storedUid = $state['uid'];

		if ($item = $this->fetchStoredToken())
		{
			$this->oauthEntity->setRefreshToken($item['REFRESH_TOKEN']);
		}

		if (!empty($_REQUEST['code']) && \CSocServAuthManager::checkUniqueKey())
		{
			$this->getAccessToken($_REQUEST['code']);

			if ($userData = $this->getUserData(false))
			{
				$fields = [
					'UID' => $this->getStoredUid(),
					'TOKEN' => $userData['__data']['access_token'],
					'REFRESH_TOKEN' => $userData['__data']['refresh_token'],
					'TOKEN_EXPIRES' => $userData['__data']['expires_in'],
				];

				if (empty($item))
				{
					Mail\Internals\OAuthTable::add($fields);
				}
				else
				{
					Mail\Internals\OAuthTable::update($item['ID'], $fields);
				}

				$userDataObject = new UserData(
					(string) $userData['email'],
					(string) $userData['first_name'],
					(string) $userData['last_name'],
					(string) $userData['full_name'],
					(string) $userData['image']
				);

				if (isset($userData['__data']['emailIsIntended']))
				{
					$userDataObject->setEmailIsIntended((bool)$userData['__data']['emailIsIntended']);
				}
				else
				{
					$userDataObject->setEmailIsIntended(false);
				}

				if (isset($userData['__data']['userPrincipalName']))
				{
					$userDataObject->setUserPrincipalName((string)$userData['__data']['userPrincipalName']);
				}

				$this->setPublicUserData($userDataObject);

				return true;
			}
		}

        return false;
	}

	protected function setPublicUserData(UserData $userData): void
	{
		$this->publicUserData = $userData;
	}

	public function getPublicUserData(): UserData
	{
		return $this->publicUserData;
	}

	/**
	 * Handles service response
	 *
	 * @param array $state Response data.
	 * @return void
	 */
	public function handleResponse(array $state, $context = self::WEB_TYPE): void
	{
        if ($this->saveResponse($state))
        {
			if ($context === self::WEB_TYPE)
			{
				?>

				<script type="text/javascript">

					targetWindow = window.opener ? window.opener : window;

					targetWindow.BX.onCustomEvent(
						'OnMailOAuthBCompleted',
						[
							'<?=\CUtil::jsEscape($this->getStoredUid()) ?>',
							'<?=\CUtil::jsEscape($this->getUrl()) ?>',
							<?=$this->getPublicUserData()->getJson() ?>
						]
					);

					if (targetWindow !== window)
					{
						window.close();
					}

				</script>

				<?
			}
			else if ($context === self::MOBILE_TYPE)
			{
				$params = http_build_query([
					'storedUid' => \CUtil::jsEscape($this->getStoredUid()),
					'email' => $this->getPublicUserData()->getEmail(),
				]);
				header('Location: bitrix24://?'.$params);
			}
        }
    }
}

Anon7 - 2022
AnonSec Team