3use \Bitrix\Main\Web\HttpClient;
12 public const ID =
"GoogleOAuth";
24 if(!$this->entityOAuth)
31 $this->entityOAuth->setCode(
$code);
34 return $this->entityOAuth;
40 [
"google_appid",
GetMessage(
"socserv_google_client_id"),
"", [
"text", 40]],
41 [
"google_appsecret",
GetMessage(
"socserv_google_client_secret"),
"", [
"text", 40]],
42 [
'google_app_api_key',
GetMessage(
'socserv_google_api_key'),
'', [
'text', 40]],
45 'socserv_google_note_2_MSGVER_1',
48 '#MAIL_URL#' => \CHttp::urn2uri(
'/bitrix/tools/mail_oauth.php'),
57 return self::GetOption(
'google_appid') !==
''
58 && self::GetOption(
'google_appsecret') !==
'';
66 $isForIntranet =
$params[
'FOR_INTRANET'] ??
false;
72 $phrase = $isForIntranet ? GetMessage("socserv_google_form_note_intranet
") : GetMessage("socserv_google_form_note
");
74 return '<a href="javascript:void(0)
" onclick="BX.util.popup(\
''.
htmlspecialcharsbx(CUtil::JSEscape(
$url)).
'\', 580, 400)
" class="bx-ss-button google-button
"></a><span class="bx-spacer
"></span><span>'.$phrase.'</span>';
77 public function GetOnClickJs($arParams)
79 $url = static::getUrl('opener', null, $arParams);
80 return "BX.util.popup(
'".CUtil::JSEscape($url)."', 580, 400)
";
83 public function getUrl($location = 'opener', $addScope = null, $arParams = array())
85 $this->entityOAuth = $this->getEntityOAuth();
87 if ($this->userId === null)
89 $this->entityOAuth->setRefreshToken("skip
");
92 if ($addScope !== null)
94 $this->entityOAuth->addScope($addScope);
106 if (IsModuleInstalled('bitrix24') && defined('BX24_HOST_NAME'))
108 $redirect_uri = static::getControllerUrl()."/redirect.php
";
109 $state = $this->getEntityOAuth()->getRedirectUri()."?check_key=
".\CSocServAuthManager::getUniqueKey()."&state=
";
110 $backurl = $GLOBALS["APPLICATION
"]->GetCurPageParam('', $removeParams);
111 $state .= urlencode('provider='.static::ID.
112 "&state=
".urlencode("backurl=
".urlencode($backurl)
113 .'&mode='.$location.(isset($arParams['BACKURL'])
114 ? '&redirect_url='.urlencode($arParams['BACKURL'])
120 $state = 'provider='.static::ID.'&site_id='.SITE_ID
121 .'&backurl='.urlencode($GLOBALS["APPLICATION
"]->GetCurPageParam('check_key='.\CSocServAuthManager::getUniqueKey(), $removeParams))
122 .'&mode='.$location.(isset($arParams['BACKURL'])
123 ? '&redirect_url='.urlencode($arParams['BACKURL'])
126 $redirect_uri = $this->getEntityOAuth()->getRedirectUri();
129 return $this->entityOAuth->GetAuthUrl($redirect_uri, $state, $arParams['APIKEY'] ?? '');
132 public function getStorageToken()
135 $userId = intval($this->userId);
138 $dbSocservUser = \Bitrix\Socialservices\UserTable::getList([
139 'filter' => ['=USER_ID' => $userId, "=EXTERNAL_AUTH_ID
" => static::ID],
140 'select' => ["OATOKEN
", "REFRESH_TOKEN
", "OATOKEN_EXPIRES
"]
142 if($arOauth = $dbSocservUser->fetch())
144 $accessToken = $arOauth["OATOKEN
"];
146 if(empty($accessToken) || ((intval($arOauth["OATOKEN_EXPIRES
"]) > 0) && (intval($arOauth["OATOKEN_EXPIRES
"] < intval(time())))))
148 if(isset($arOauth['REFRESH_TOKEN']))
150 $this->getEntityOAuth()->getNewAccessToken($arOauth['REFRESH_TOKEN'], $userId, true);
153 if(($accessToken = $this->getEntityOAuth()->getToken()) === false)
164 public function prepareUser($arGoogleUser, $short = false)
168 if(is_array($arGoogleUser['name']))
170 $first_name = $arGoogleUser['name']['givenName'];
171 $last_name = $arGoogleUser['name']['familyName'];
173 elseif(!empty($arGoogleUser['name']))
175 $aName = explode(" ", $arGoogleUser['name']);
176 if(!empty($arGoogleUser['given_name']))
178 $first_name = $arGoogleUser['given_name'];
182 $first_name = $aName[0];
185 if(!empty($arGoogleUser['family_name']))
187 $last_name = $arGoogleUser['family_name'];
189 elseif(!empty($aName[1]))
191 $last_name = $aName[1];
195 $id = $arGoogleUser['id'] ?? $arGoogleUser['sub'];
196 $email = $arGoogleUser['email'];
198 if(!empty($arGoogleUser['email']))
200 $dbRes = \Bitrix\Main\UserTable::getList(array(
202 '=EXTERNAL_AUTH_ID' => 'socservices',
205 'select' => array('ID'),
215 'EXTERNAL_AUTH_ID' => static::ID,
217 'LOGIN' => static::LOGIN_PREFIX.$id,
219 'NAME'=> $first_name,
220 'LAST_NAME'=> $last_name,
221 'OATOKEN' => $this->entityOAuth->getToken(),
222 'OATOKEN_EXPIRES' => $this->entityOAuth->getAccessTokenExpires(),
223 'REFRESH_TOKEN' => $this->entityOAuth->getRefreshToken(),
226 if(!empty($arGoogleUser['gender']))
228 if($arGoogleUser['gender'] === 'male')
230 $arFields["PERSONAL_GENDER
"] = 'M';
232 elseif($arGoogleUser['gender'] === 'female')
234 $arFields["PERSONAL_GENDER
"] = 'F';
238 if(!$short && isset($arGoogleUser['picture']) && $this->CheckPhotoURI($arGoogleUser['picture']))
240 $arGoogleUser['picture'] = preg_replace("/\?.*$/
", '', $arGoogleUser['picture']);
242 if ($arGoogleUser['picture'])
244 $temp_path = CFile::GetTempName('', sha1($arGoogleUser['picture']));
246 $http = new HttpClient();
247 $http->setPrivateIp(false);
248 if($http->download($arGoogleUser['picture'], $temp_path))
250 $arPic = CFile::MakeFileArray($temp_path);
256 $arFields["PERSONAL_PHOTO
"] = $arPic;
260 $arFields["PERSONAL_WWW
"] = $arGoogleUser['link'] ?? $arGoogleUser['url'];
264 $arFields["SITE_ID"] = SITE_ID;
270 public function Authorize()
273 $APPLICATION->RestartBuffer();
276 $bProcessState = false;
278 $authError = SOCSERV_AUTHORISATION_ERROR;
280 if(!empty($_REQUEST["code
"]) && CSocServAuthManager::CheckUniqueKey())
282 $this->getEntityOAuth()->setCode($_REQUEST["code
"]);
284 $bProcessState = true;
286 if($this->getEntityOAuth()->GetAccessToken() !== false)
288 $arGoogleUser = $this->getEntityOAuth()->GetCurrentUser();
290 if(is_array($arGoogleUser) && !isset($arGoogleUser["error
"]))
292 $arFields = $this->prepareUser($arGoogleUser);
293 $authError = $this->AuthorizeUser($arFields);
300 unset($_REQUEST["state
"]);
303 $bSuccess = $authError === true;
305 $aRemove = ["logout
", "auth_service_error
", "auth_service_id
", "code
", "error_reason
", "error
", "error_description
", "check_key
", "current_fieldset
"];
310 CSocServUtil::checkOAuthProxyParams();
312 $url = ($APPLICATION->GetCurDir() === "/login/
") ? "" : $APPLICATION->GetCurDir();
315 if(isset($_REQUEST["state
"]))
318 parse_str($_REQUEST["state
"], $arState);
320 if(isset($arState['backurl']) || isset($arState['redirect_url']))
322 $url = !empty($arState['redirect_url']) ? $arState['redirect_url'] : $arState['backurl'];
323 if (!str_starts_with($url, "#
"))
325 $parseUrl = parse_url($url);
327 $urlPath = $parseUrl["path"];
328 $arUrlQuery = explode('&', $parseUrl["query
"]);
330 foreach($arUrlQuery as $key => $value)
332 foreach($aRemove as $param)
334 if (str_starts_with($value, $param . "=
"))
336 unset($arUrlQuery[$key]);
342 $url = (!empty($arUrlQuery)) ? $urlPath . '?' . implode("&
", $arUrlQuery) : $urlPath;
350 if(isset($arState['mode']))
352 $mode = $arState['mode'];
357 if ($authError === SOCSERV_REGISTRATION_DENY)
359 $url = (preg_match("/\?/
", $url)) ? $url.'&' : $url.'?';
360 $url .= 'auth_service_id='.static::ID.'&auth_service_error='.SOCSERV_REGISTRATION_DENY;
362 elseif ($bSuccess !== true)
364 $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);
367 if($addParams && CModule::IncludeModule("socialnetwork
") && mb_strpos($url, "current_fieldset=
") === false)
369 $url = (preg_match("/\?/
", $url)) ? $url."¤t_fieldset=SOCSERV
" : $url."?current_fieldset=SOCSERV
";
372 $url = CUtil::JSEscape($url);
374 if ($bSuccess && $mode === self::MOBILE_MODE)
376 $this->onAfterMobileAuth();
380 $this->onAfterWebAuth($addParams, $mode, $url);
383 CMain::FinalActions();
386 public function setUser($userId)
388 $this->getEntityOAuth()->setUser($userId);
391 public function getFriendsList($limit, &$next)
395 if($this->getEntityOAuth()->GetAccessToken() !== false)
397 $res = $this->getEntityOAuth()->getCurrentUserFriends($limit, $next);
399 foreach($res as $key => $contact)
401 $contact['uid'] = $contact['email'];
403 $arName = $contact['name'];
405 $contact['first_name'] = trim($arName['givenName']);
406 $contact['last_name'] = trim($arName['familyName']);
407 $contact['second_name'] = trim($arName['additionalName']);
409 if(!$contact['first_name'] && !$contact['last_name'])
411 $contact['first_name'] = $contact['uid'];
414 $res[$key] = $contact;
422class CGoogleOAuthInterface extends CSocServOAuthTransport
424 const SERVICE_ID = "GoogleOAuth
";
426 public const CERTS_URL = "https:
429 const AUTH_URL =
"https://accounts.google.com/o/oauth2/auth";
430 const TOKEN_URL =
"https://accounts.google.com/o/oauth2/token";
432 const FRIENDS_URL =
"https://www.google.com/m8/feeds/contacts/default/full";
438 'https://www.googleapis.com/auth/userinfo.email',
439 'https://www.googleapis.com/auth/userinfo.profile',
453 $appID = trim(CSocServGoogleOAuth::GetOption(
"google_appid"));
458 $appSecret = trim(CSocServGoogleOAuth::GetOption(
"google_appsecret"));
461 $this->scope = $this->standardScope;
470 return 'saved_scope_'.static::SERVICE_ID;
478 $savedScope = unserialize($savedScope, [
'allowed_classes' =>
false]);
479 if(is_array($savedScope))
481 $this->scope = array_merge($this->scope, $savedScope);
488 $scope = array_unique(array_diff($this->scope, $this->standardScope));
503 parent::removeScope(
$scope);
510 return implode(
'+', array_map(
'urlencode', array_unique($this->
getScope())));
520 return is_array($this->arResult) && isset($this->arResult[
'error'])
521 ? $this->arResult[
'error']
525 public function GetAuthUrl($redirect_uri, $state =
'', $apiKey =
'')
527 return static::AUTH_URL.
528 "?client_id=".urlencode($this->appID).
529 "&redirect_uri=".urlencode($redirect_uri).
530 "&scope=".$this->getScopeEncode().
531 "&response_type=code".
532 "&access_type=offline".
533 ($this->refresh_token <>
'' ?
'' :
'&approval_prompt=force').
534 ($state <>
'' ?
'&state='.urlencode($state) :
'').
535 ($apiKey !==
'' ?
'&key=' . urlencode($apiKey) :
'')
541 $this->idTokenAuth = $tokenId;
544 private function fetchPublicKeys(): ?
array
546 if ($this->fetchedPublicKeys)
548 return $this->fetchedPublicKeys;
553 $publicKeys = $this->getDecodedJson(self::CERTS_URL);
554 if (empty($publicKeys[
'keys']) ||
count($publicKeys[
'keys']) < 1)
559 $parsedPublicKeys = JWK::parseKeySet($publicKeys[
'keys']);
560 foreach ($parsedPublicKeys as $keyId => $publicKey)
562 $details = openssl_pkey_get_details($publicKey);
563 $this->fetchedPublicKeys[$keyId] = $details[
'key'];
566 return $this->fetchedPublicKeys;
568 catch (\Exception $e)
575 private function decodeIdentityToken(
string $identityToken):
array
577 $publicKeys = $this->fetchPublicKeys();
578 if ($publicKeys ===
null)
585 return (
array)JWT::decode($identityToken, $publicKeys, self::JWT_ALG);
587 catch (UnexpectedValueException $exception)
597 if(is_array($tokens))
599 $this->access_token = $tokens[
"OATOKEN"];
600 $this->accessTokenExpires = $tokens[
"OATOKEN_EXPIRES"];
608 elseif(isset($tokens[
"REFRESH_TOKEN"]))
620 if($this->code ===
false)
625 if($redirect_uri ===
false)
629 $redirect_uri = \CSocServGoogleOAuth::getControllerUrl().
"/redirect.php";
638 "client_id" => $this->appID,
640 "redirect_uri" => $redirect_uri,
641 "grant_type" =>
"authorization_code",
642 "client_secret" => $this->appSecret,
645 $this->arResult = $this->
getDecodedJson(static::TOKEN_URL, $authParams);
647 if(isset($this->arResult[
"access_token"]) && $this->arResult[
"access_token"] <>
'')
649 if(isset($this->arResult[
"refresh_token"]) && $this->arResult[
"refresh_token"] <>
'')
651 $this->refresh_token = $this->arResult[
"refresh_token"];
653 $this->access_token = $this->arResult[
"access_token"];
654 $this->accessTokenExpires = $this->arResult[
"expires_in"] + time();
656 $_SESSION[
"OAUTH_DATA"] =
array(
657 "OATOKEN" => $this->access_token,
658 "OATOKEN_EXPIRES" => $this->accessTokenExpires,
659 "REFRESH_TOKEN" => $this->refresh_token,
669 if ($this->idTokenAuth)
671 $identity = $this->decodeIdentityToken($this->idTokenAuth);
673 return $identity ?:
false;
676 if($this->access_token ===
false)
679 $result = $this->
getDecodedJson(static::CONTACTS_URL.
'?access_token='.urlencode($this->access_token));
683 $result[
"access_token"] = $this->access_token;
684 $result[
"refresh_token"] = $this->refresh_token;
685 $result[
"expires_in"] = $this->accessTokenExpires;
693 if ($this->idTokenAuth)
695 $identity = $this->decodeIdentityToken($this->idTokenAuth);
696 if (empty($identity[
'aud']))
702 'id' => $identity[
'aud'],
705 if ($this->access_token ===
false)
710 $result = $this->
getDecodedJson(static::TOKENINFO_URL.
'?access_token='.urlencode($this->access_token));
722 if($this->access_token ===
false)
726 $http->setHeader(
'GData-Version',
'3.0');
727 $http->setHeader(
'Authorization',
'Bearer '.$this->access_token);
729 $url = static::FRIENDS_URL.
'?';
731 $limit = (int)$limit;
736 $url .=
'&max-results='.$limit;
741 $url .=
'&start-index='.$next;
746 if((
int)$http->getStatus() === 200)
748 $obXml = new \CDataXML();
749 if($obXml->loadString(
$result))
751 $tree = $obXml->getTree();
753 $total = $tree->elementsByName(
"totalResults");
754 $total = (int)$total[0]->textContent();
756 $limitNode = $tree->elementsByName(
"itemsPerPage");
757 $next += (int)$limitNode[0]->textContent();
761 $next =
'__finish__';
764 $arFriends =
array();
765 $arEntries = $tree->elementsByName(
'entry');
766 foreach($arEntries as $entry)
769 $entryChildren = $entry->children();
771 foreach ($entryChildren as $child)
773 $tag = $child->name();
783 $arEntry[$tag] =
array();
784 foreach($child->children() as $subChild)
786 $arEntry[$tag][$subChild->name()] = $subChild->textContent();
792 if($child->getAttribute(
'primary') ==
'true')
794 $arEntry[$tag] = $child->getAttribute(
'address');
800 $tagContent = $tag ==
'link'
801 ? $child->getAttribute(
'href')
802 : $child->textContent();
804 if($child->getAttribute(
'rel'))
806 if(!isset($arEntry[$tag]))
808 $arEntry[$tag] =
array();
811 $arEntry[$tag][preg_replace(
"/^[^#]*#/",
"", $child->getAttribute(
'rel'))] = $tagContent;
813 elseif(isset($arEntry[$tag]))
815 if(!is_array($arEntry[$tag][0]) || !isset($arEntry[$tag][0]))
817 $arEntry[$tag] =
array($arEntry[$tag], $tagContent);
821 $arEntry[$tag][] = $tagContent;
826 $arEntry[$tag] = $tagContent;
831 if($arEntry[
'email'])
833 $arFriends[] = $arEntry;
845 if($this->appID ==
false || $this->appSecret ==
false)
850 if($refreshToken ===
false)
852 $refreshToken = $this->refresh_token;
856 "client_id" => $this->appID,
857 "refresh_token"=>$refreshToken,
858 "grant_type"=>
"refresh_token",
859 "client_secret" => $this->appSecret,
862 if (isset($this->arResult[
"access_token"]) && $this->arResult[
"access_token"] <>
'')
864 $this->access_token = $this->arResult[
"access_token"];
865 $this->accessTokenExpires = $this->arResult[
"expires_in"] + time();
868 $dbSocservUser = \Bitrix\Socialservices\UserTable::getList(
array(
870 '=EXTERNAL_AUTH_ID' => static::SERVICE_ID,
873 'select' =>
array(
"ID")
875 if($arOauth = $dbSocservUser->Fetch())
877 \Bitrix\Socialservices\UserTable::update($arOauth[
"ID"],
array(
878 "OATOKEN" => $this->access_token,
879 "OATOKEN_EXPIRES" => $this->accessTokenExpires)
892 return \CHTTP::URN2URI(static::REDIRECT_URI);
change_password_forgot_link login popup forget pas AUTH_GOTO_FORGOT_FORM login btn wrap change_password_button login popup link login popup return auth javascript
static get($moduleId, $name, $default="", $siteId=false)
static set($moduleId, $name, $value="", $siteId="")
GetAuthUrl($redirect_uri, $state='', $apiKey='')
__construct($appID=false, $appSecret=false, $code=false)
getNewAccessToken($refreshToken=false, $userId=0, $save=false)
GetCurrentUserFriends($limit, &$next)
setIdTokenAuth(string $tokenId)
removeScope(string $scope)
GetAccessToken($redirect_uri=false)
getEntityOAuth($code=false)
getDecodedJson($url, $postData=null)
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
if(!is_null($config))($config as $configItem)(! $configItem->isVisible()) $code
IsModuleInstalled($module_id)
htmlspecialcharsbx($string, $flags=ENT_COMPAT, $doubleEncode=true)
IncludeModuleLangFile($filepath, $lang=false, $bReturnArray=false)
GetMessage($name, $aReplace=null)
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
</p ></td >< td valign=top style='border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 2.0pt 0cm 2.0pt;height:9.0pt'>< p class=Normal align=center style='margin:0cm;margin-bottom:.0001pt;text-align:center;line-height:normal'>< a name=ТекстовоеПоле54 ></a ><?=($taxRate > count( $arTaxList) > 0) ? $taxRate."%"
if($inWords) echo htmlspecialcharsbx(Number2Word_Rus(roundEx($totalVatSum $params['CURRENCY']