PageRenderTime 43ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/socialservices/classes/general/yandex.php

https://gitlab.com/alexprowars/bitrix
PHP | 474 lines | 378 code | 80 blank | 16 comment | 56 complexity | 92b3cf053864726541bc2f90e11daba3 MD5 | raw file
  1. <?
  2. IncludeModuleLangFile(__FILE__);
  3. class CSocServYandexAuth extends CSocServAuth
  4. {
  5. const ID = "YandexOAuth";
  6. const CONTROLLER_URL = "https://www.bitrix24.ru/controller";
  7. const LOGIN_PREFIX = "YA_";
  8. /** @var CYandexOAuthInterface null */
  9. protected $entityOAuth = null;
  10. /**
  11. * @param string $code=false
  12. * @return CYandexOAuthInterface
  13. */
  14. public function getEntityOAuth($code = false)
  15. {
  16. if(!$this->entityOAuth)
  17. {
  18. $this->entityOAuth = new CYandexOAuthInterface();
  19. }
  20. if($code !== false)
  21. {
  22. $this->entityOAuth->setCode($code);
  23. }
  24. return $this->entityOAuth;
  25. }
  26. public function GetSettings()
  27. {
  28. return array(
  29. array("yandex_appid", GetMessage("socserv_yandex_client_id"), "", array("text", 40)),
  30. array("yandex_appsecret", GetMessage("socserv_yandex_client_secret"), "", array("text", 40)),
  31. array(
  32. 'note' => getMessage(
  33. 'socserv_yandex_note_2',
  34. array(
  35. '#URL#' => \CYandexOAuthInterface::getRedirectUri(),
  36. '#MAIL_URL#' => \CHttp::urn2uri('/bitrix/tools/mail_oauth.php'),
  37. )
  38. ),
  39. ),
  40. );
  41. }
  42. public function getUrl($location = 'opener', $addScope = null, $arParams = array())
  43. {
  44. global $APPLICATION;
  45. $this->entityOAuth = $this->getEntityOAuth();
  46. CSocServAuthManager::SetUniqueKey();
  47. if(IsModuleInstalled('bitrix24') && defined('BX24_HOST_NAME'))
  48. {
  49. $redirect_uri = static::CONTROLLER_URL."/redirect.php";
  50. $state = CYandexOAuthInterface::GetRedirectURI()."?check_key=".$_SESSION["UNIQUE_KEY"]."&state=";
  51. $backurl = $APPLICATION->GetCurPageParam('', array("logout", "auth_service_error", "auth_service_id", "backurl"));
  52. $state .= urlencode("state=".urlencode("backurl=".urlencode($backurl).'&mode='.$location.(isset($arParams['BACKURL']) ? '&redirect_url='.urlencode($arParams['BACKURL']) : '')));
  53. }
  54. else
  55. {
  56. $state = 'site_id='.SITE_ID.'&backurl='.urlencode($APPLICATION->GetCurPageParam('check_key='.$_SESSION["UNIQUE_KEY"], array("logout", "auth_service_error", "auth_service_id", "backurl"))).'&mode='.$location.(isset($arParams['BACKURL']) ? '&redirect_url='.urlencode($arParams['BACKURL']) : '');
  57. $redirect_uri = CYandexOAuthInterface::GetRedirectURI();
  58. }
  59. return $this->entityOAuth->GetAuthUrl($redirect_uri, $state);
  60. }
  61. public function GetFormHtml($arParams)
  62. {
  63. $url = static::getUrl('opener', null, $arParams);
  64. $phrase = ($arParams["FOR_INTRANET"]) ? GetMessage("socserv_yandex_form_note_intranet") : GetMessage("socserv_yandex_form_note");
  65. if($arParams["FOR_INTRANET"])
  66. {
  67. return array("ON_CLICK" => 'onclick="BX.util.popup(\''.htmlspecialcharsbx(CUtil::JSEscape($url)).'\', 680, 600)"');
  68. }
  69. else
  70. {
  71. return '<a href="javascript:void(0)" onclick="BX.util.popup(\''.htmlspecialcharsbx(CUtil::JSEscape($url)).'\', 680, 600)" class="bx-ss-button yandex-button"></a><span class="bx-spacer"></span><span>'.$phrase.'</span>';
  72. }
  73. }
  74. public function GetOnClickJs($arParams)
  75. {
  76. $url = static::getUrl('opener', null, $arParams);
  77. return "BX.util.popup('".CUtil::JSEscape($url)."', 680, 600)";
  78. }
  79. public function getStorageToken()
  80. {
  81. $accessToken = null;
  82. $userId = intval($this->userId);
  83. if($userId > 0)
  84. {
  85. $dbSocservUser = \Bitrix\Socialservices\UserTable::getList([
  86. 'filter' => ['=USER_ID' => $userId, "=EXTERNAL_AUTH_ID" => static::ID],
  87. 'select' => ["OATOKEN", "REFRESH_TOKEN", "OATOKEN_EXPIRES"]
  88. ]);
  89. if($arOauth = $dbSocservUser->fetch())
  90. {
  91. $accessToken = $arOauth["OATOKEN"];
  92. }
  93. }
  94. return $accessToken;
  95. }
  96. public function prepareUser($yandexUser, $short = false)
  97. {
  98. $id = $yandexUser['id'];
  99. $userFields = array(
  100. 'EXTERNAL_AUTH_ID' => static::ID,
  101. 'XML_ID' => $id,
  102. 'LOGIN' => static::LOGIN_PREFIX.$id,
  103. 'NAME'=> $yandexUser['first_name'],
  104. 'LAST_NAME'=> $yandexUser['last_name'],
  105. 'OATOKEN' => $this->entityOAuth->getToken(),
  106. 'OATOKEN_EXPIRES' => $this->entityOAuth->getAccessTokenExpires(),
  107. );
  108. if($userFields["NAME"] == '')
  109. {
  110. $userFields["NAME"] = $yandexUser["login"];
  111. }
  112. if(isset($yandexUser["emails"]) && is_array($yandexUser["emails"]) && count($yandexUser["emails"]) > 0)
  113. {
  114. $userFields["EMAIL"] = $yandexUser['emails'][0];
  115. }
  116. if(!$short && !empty($yandexUser['default_avatar_id']))
  117. {
  118. $picture_url = "https://avatars.yandex.net/get-yapic/".$yandexUser["default_avatar_id"]."/islands-200";
  119. $temp_path = CFile::GetTempName('', 'picture.jpg');
  120. $ob = new \Bitrix\Main\Web\HttpClient(array(
  121. "redirect" => true
  122. ));
  123. $ob->download($picture_url, $temp_path);
  124. $arPic = CFile::MakeFileArray($temp_path);
  125. if($arPic)
  126. {
  127. $userFields["PERSONAL_PHOTO"] = $arPic;
  128. }
  129. }
  130. if(SITE_ID <> '')
  131. {
  132. $userFields["SITE_ID"] = SITE_ID;
  133. }
  134. return $userFields;
  135. }
  136. public function Authorize()
  137. {
  138. global $APPLICATION;
  139. $APPLICATION->RestartBuffer();
  140. $bSuccess = false;
  141. $bProcessState = false;
  142. $authError = SOCSERV_AUTHORISATION_ERROR;
  143. if(
  144. isset($_REQUEST["code"]) && $_REQUEST["code"] <> '' && CSocServAuthManager::CheckUniqueKey()
  145. )
  146. {
  147. $bProcessState = true;
  148. $this->entityOAuth = $this->getEntityOAuth($_REQUEST['code']);
  149. if(IsModuleInstalled('bitrix24') && defined('BX24_HOST_NAME'))
  150. {
  151. $redirect_uri = static::CONTROLLER_URL."/redirect.php";
  152. }
  153. else
  154. {
  155. $redirect_uri = $this->getEntityOAuth()->GetRedirectURI();
  156. }
  157. if($this->entityOAuth->GetAccessToken($redirect_uri) !== false)
  158. {
  159. $boxUser = $this->entityOAuth->GetCurrentUser();
  160. if(is_array($boxUser))
  161. {
  162. $arFields = self::prepareUser($boxUser);
  163. $authError = $this->AuthorizeUser($arFields);
  164. $bSuccess = $authError === true;
  165. }
  166. }
  167. }
  168. $url = ($APPLICATION->GetCurDir() == "/login/") ? "" : $APPLICATION->GetCurDir();
  169. $aRemove = array("logout", "auth_service_error", "auth_service_id", "code", "error_reason", "error", "error_description", "check_key", "current_fieldset");
  170. if(!$bProcessState)
  171. {
  172. unset($_REQUEST["state"]);
  173. }
  174. $mode = 'opener';
  175. $addParams = true;
  176. if(isset($_REQUEST["state"]))
  177. {
  178. $arState = array();
  179. parse_str($_REQUEST["state"], $arState);
  180. if(isset($arState['backurl']) || isset($arState['redirect_url']))
  181. {
  182. $url = !empty($arState['redirect_url']) ? $arState['redirect_url'] : $arState['backurl'];
  183. if(mb_substr($url, 0, 1) !== "#")
  184. {
  185. $parseUrl = parse_url($url);
  186. $urlPath = $parseUrl["path"];
  187. $arUrlQuery = explode('&', $parseUrl["query"]);
  188. foreach($arUrlQuery as $key => $value)
  189. {
  190. foreach($aRemove as $param)
  191. {
  192. if(mb_strpos($value, $param."=") === 0)
  193. {
  194. unset($arUrlQuery[$key]);
  195. break;
  196. }
  197. }
  198. }
  199. $url = (!empty($arUrlQuery)) ? $urlPath.'?'.implode("&", $arUrlQuery) : $urlPath;
  200. }
  201. else
  202. {
  203. $addParams = false;
  204. }
  205. }
  206. if(isset($arState['mode']))
  207. {
  208. $mode = $arState['mode'];
  209. }
  210. }
  211. if($authError === SOCSERV_REGISTRATION_DENY)
  212. {
  213. $url = (preg_match("/\?/", $url)) ? $url.'&' : $url.'?';
  214. $url .= 'auth_service_id='.static::ID.'&auth_service_error='.SOCSERV_REGISTRATION_DENY;
  215. }
  216. elseif($bSuccess !== true)
  217. {
  218. $url = (isset($urlPath)) ? $urlPath.'?auth_service_id='.static::ID.'&auth_service_error='.$authError : $APPLICATION->GetCurPageParam(('auth_service_id='.static::ID.'&auth_service_error='.$authError), $aRemove);
  219. }
  220. if($addParams && CModule::IncludeModule("socialnetwork") && mb_strpos($url, "current_fieldset=") === false)
  221. {
  222. $url = (preg_match("/\?/", $url)) ? $url."&current_fieldset=SOCSERV" : $url."?current_fieldset=SOCSERV";
  223. }
  224. $url = CUtil::JSEscape($url);
  225. if($addParams)
  226. {
  227. $location = ($mode == "opener") ? 'if(window.opener) window.opener.location = \''.$url.'\'; window.close();' : ' window.location = \''.$url.'\';';
  228. }
  229. else
  230. {
  231. //fix for chrome
  232. $location = ($mode == "opener") ? 'if(window.opener) window.opener.location = window.opener.location.href + \''.$url.'\'; window.close();' : ' window.location = window.location.href + \''.$url.'\';';
  233. }
  234. $JSScript = '
  235. <script type="text/javascript">
  236. '.$location.'
  237. </script>
  238. ';
  239. echo $JSScript;
  240. die();
  241. }
  242. }
  243. class CYandexOAuthInterface extends CSocServOAuthTransport
  244. {
  245. const SERVICE_ID = "YandexOAuth";
  246. const AUTH_URL = "https://oauth.yandex.ru/authorize";
  247. const TOKEN_URL = "https://oauth.yandex.ru/token";
  248. const USERINFO_URL = "https://login.yandex.ru/info";
  249. const MAX_DEVICE_ID_LENGTH = 50;
  250. protected $arResult = array();
  251. public function __construct($appID = false, $appSecret = false, $code = false)
  252. {
  253. if($appID === false)
  254. {
  255. $appID = trim(CSocServYandexAuth::GetOption("yandex_appid"));
  256. }
  257. if($appSecret === false)
  258. {
  259. $appSecret = trim(CSocServYandexAuth::GetOption("yandex_appsecret"));
  260. }
  261. parent::__construct($appID, $appSecret, $code);
  262. }
  263. public static function GetRedirectURI()
  264. {
  265. return \CHTTP::URN2URI("/bitrix/tools/oauth/yandex.php");
  266. }
  267. public function getResult()
  268. {
  269. return $this->arResult;
  270. }
  271. public function getError()
  272. {
  273. return is_array($this->arResult) && isset($this->arResult['error'])
  274. ? $this->arResult['error']
  275. : '';
  276. }
  277. /**
  278. * @param string $redirect_uri
  279. * @param string $state
  280. * @return string
  281. */
  282. public function GetAuthUrl($redirect_uri = '', $state = '')
  283. {
  284. $deviceId = $this->getDeviceId($state);
  285. return self::AUTH_URL
  286. ."?response_type=code"
  287. ."&client_id=".urlencode($this->appID)
  288. .(!empty($deviceId) ? "&device_id=".$deviceId : '')
  289. ."&display=popup"
  290. ."&redirect_uri=".urlencode($redirect_uri)
  291. .'&force_confirm=yes'
  292. .(!empty($state) ? "&state=".urlencode($state) : '');
  293. }
  294. /**
  295. * @param string $state
  296. * @return string
  297. */
  298. public function getDeviceId($state)
  299. {
  300. $deviceId = '';
  301. if (!empty($state) && isset($_SESSION[$state]))
  302. {
  303. list(, $deviceId) = $_SESSION[$state];
  304. if ($deviceId)
  305. {
  306. $deviceId = mb_substr($deviceId, 0, self::MAX_DEVICE_ID_LENGTH);
  307. }
  308. }
  309. return $deviceId;
  310. }
  311. public function GetAccessToken()
  312. {
  313. if(($tokens = $this->getStorageTokens()) && is_array($tokens))
  314. {
  315. $this->access_token = $tokens["OATOKEN"];
  316. if(!$this->code)
  317. {
  318. if($this->checkAccessToken())
  319. {
  320. return true;
  321. }
  322. }
  323. $this->deleteStorageTokens();
  324. }
  325. if($this->code === false)
  326. {
  327. return false;
  328. }
  329. $h = new \Bitrix\Main\Web\HttpClient(array("socketTimeout" => $this->httpTimeout));
  330. $h->setAuthorization($this->appID, $this->appSecret);
  331. $result = $h->post(self::TOKEN_URL, array(
  332. "grant_type"=>"authorization_code",
  333. "code"=>$this->code,
  334. "client_id" => $this->appID,
  335. ));
  336. $this->arResult = \Bitrix\Main\Web\Json::decode($result);
  337. if(isset($this->arResult["access_token"]) && $this->arResult["access_token"] <> '')
  338. {
  339. // yandex doesn't send refresh tokens but I leave it here in case they will
  340. if(isset($this->arResult["refresh_token"]) && $this->arResult["refresh_token"] <> '')
  341. {
  342. $this->refresh_token = $this->arResult["refresh_token"];
  343. }
  344. $this->access_token = $this->arResult["access_token"];
  345. $this->accessTokenExpires = $this->arResult["expires_in"] + time();
  346. $_SESSION["OAUTH_DATA"] = array(
  347. "OATOKEN" => $this->access_token,
  348. );
  349. return true;
  350. }
  351. return false;
  352. }
  353. public function GetCurrentUser()
  354. {
  355. if($this->access_token === false)
  356. return false;
  357. $h = new \Bitrix\Main\Web\HttpClient();
  358. $result = $h->get(self::USERINFO_URL.'?format=json&oauth_token='.urlencode($this->access_token));
  359. try
  360. {
  361. $result = \Bitrix\Main\Web\Json::decode($result);
  362. }
  363. catch(\Bitrix\Main\SystemException $e)
  364. {
  365. $result = false;
  366. }
  367. if(is_array($result))
  368. {
  369. $result["access_token"] = $this->access_token;
  370. $result["refresh_token"] = $this->refresh_token;
  371. $result["expires_in"] = $this->accessTokenExpires;
  372. }
  373. return $result;
  374. }
  375. public function GetAppInfo()
  376. {
  377. if ($this->access_token === false)
  378. return false;
  379. $h = new \Bitrix\Main\Web\HttpClient();
  380. $h->setTimeout($this->httpTimeout);
  381. $result = $h->get(self::USERINFO_URL.'?format=json&oauth_token='.urlencode($this->access_token));
  382. try
  383. {
  384. $result = \Bitrix\Main\Web\Json::decode($result);
  385. $result = array_key_exists("client_id", $result)
  386. ? array("id" => $result["client_id"])
  387. : array();
  388. } catch (\Bitrix\Main\ArgumentException $e)
  389. {
  390. $result = array();
  391. }
  392. return $result;
  393. }
  394. }