Exemplo n.º 1
0
 public function actionAuthorizeGuest()
 {
     $requestPaths = XenForo_Application::get('requestPaths');
     $social = $this->_input->filterSingle('social', XenForo_Input::STRING);
     switch ($social) {
         case 'facebook':
             $facebookLink = XenForo_Link::buildPublicLink('full:register/facebook', null, array('reg' => 1, 'redirect' => $requestPaths['fullUri']));
             return $this->responseRedirect(XenForo_ControllerResponse_Redirect::SUCCESS, $facebookLink);
         case 'twitter':
             $twitterLink = XenForo_Link::buildPublicLink('full:register/twitter', null, array('reg' => 1, 'redirect' => $requestPaths['fullUri']));
             return $this->responseRedirect(XenForo_ControllerResponse_Redirect::SUCCESS, $twitterLink);
     }
     /* @var $oauth2Model bdApi_Model_OAuth2 */
     $oauth2Model = $this->getModelFromCache('bdApi_Model_OAuth2');
     /* @var $clientModel bdApi_Model_Client */
     $clientModel = $oauth2Model->getClientModel();
     $clientId = $this->_input->filterSingle('client_id', XenForo_Input::STRING);
     $client = $clientModel->getClientById($clientId);
     if (empty($client)) {
         return $this->responseError(new XenForo_Phrase('bdapi_authorize_error_client_x_not_found', array('client' => $clientId)), 404);
     }
     $authorizeParams = $this->_input->filter($oauth2Model->getAuthorizeParamsInputFilter());
     $redirectParams = $authorizeParams;
     $redirectParams['timestamp'] = time() + bdApi_Option::get('authorizeBypassSecs');
     $redirectParams['hash'] = bdApi_Crypt::encryptTypeOne(serialize($authorizeParams), $redirectParams['timestamp']);
     $redirect = XenForo_Link::buildPublicLink('account/authorize', null, $redirectParams);
     $viewParams = array('client' => $client, 'authorizeParams' => $authorizeParams, 'social' => $social, 'redirect' => $redirect);
     $view = $this->responseView('bdApi_ViewPublic_Account_Authorize', 'bdapi_error_authorize_guest', $viewParams);
     $view->responseCode = 403;
     return $view;
 }
Exemplo n.º 2
0
 public function actionApi()
 {
     $input = $this->_input->filter(array('redirect' => XenForo_Input::STRING, 'timestamp' => XenForo_Input::UINT, 'user_id' => XenForo_Input::STRING));
     $userId = 0;
     if (!empty($input['user_id']) && !empty($input['timestamp'])) {
         try {
             $userId = intval(bdApi_Crypt::decryptTypeOne($input['user_id'], $input['timestamp']));
         } catch (XenForo_Exception $e) {
             if (XenForo_Application::debugMode()) {
                 $this->_response->setHeader('X-Api-Exception', $e->getMessage());
             }
         }
     }
     if ($userId > 0) {
         $this->_response->setHeader('X-Api-Login-User', $userId);
         $this->_getUserModel()->setUserRememberCookie($userId);
         XenForo_Model_Ip::log($userId, 'user', $userId, 'login_api');
         $this->_getUserModel()->deleteSessionActivity(0, $this->_request->getClientIp(false));
         $session = XenForo_Application::get('session');
         $session->changeUserId($userId);
         XenForo_Visitor::setup($userId);
     }
     if (empty($input['redirect'])) {
         $input['redirect'] = $this->getDynamicRedirectIfNot(XenForo_Link::buildPublicLink('login'));
     }
     return $this->responseRedirect(XenForo_ControllerResponse_Redirect::SUCCESS, $input['redirect']);
 }
Exemplo n.º 3
0
 public function getDynamicRedirect($fallbackUrl = false, $useReferrer = true)
 {
     $input = $this->_input->filter(array('redirect' => XenForo_Input::STRING, 'timestamp' => XenForo_Input::UINT, 'md5' => XenForo_Input::STRING));
     if (!empty($input['md5']) && md5($input['redirect']) === bdApi_Crypt::decryptTypeOne($input['md5'], $input['timestamp'])) {
         $this->_bdApi_redirect = $input['redirect'];
         return $input['redirect'];
     }
     return parent::getDynamicRedirect($fallbackUrl, $useReferrer);
 }
Exemplo n.º 4
0
 public function actionPostPasswordTest()
 {
     $input = $this->_input->filter(array('password' => XenForo_Input::STRING, 'password_algo' => XenForo_Input::STRING, 'decrypt' => XenForo_Input::UINT));
     if (!XenForo_Application::debugMode()) {
         return $this->responseNoPermission();
     }
     if (empty($input['decrypt'])) {
         $result = bdApi_Crypt::encrypt($input['password'], $input['password_algo']);
     } else {
         $result = bdApi_Crypt::decrypt($input['password'], $input['password_algo']);
     }
     $data = array('result' => $result);
     return $this->responseData('bdApi_ViewApi_Tool_PasswordTest', $data);
 }
Exemplo n.º 5
0
 public static function front_controller_pre_route(XenForo_FrontController $fc)
 {
     // use cookie flag to change web UI interface to match requested language_id from api
     $request = $fc->getRequest();
     $apiLanguageId = $request->getParam('_apiLanguageId');
     if (!empty($apiLanguageId) && preg_match('#^(?<timestamp>\\d+) (?<data>.+)$#', $apiLanguageId, $matches)) {
         try {
             $languageId = bdApi_Crypt::decryptTypeOne($matches['data'], $matches['timestamp']);
             if ($languageId > 0) {
                 $cookiePrefix = XenForo_Application::getConfig()->get('cookie')->get('prefix');
                 XenForo_Helper_Cookie::setCookie('language_id', $languageId);
                 $_COOKIE[$cookiePrefix . 'language_id'] = $languageId;
                 $fc->getResponse()->setHeader('X-Api-Language', $languageId);
             }
         } catch (XenForo_Exception $e) {
             // ignore
         }
     }
 }
Exemplo n.º 6
0
 public function getDynamicRedirect($fallbackUrl = false, $useReferrer = true)
 {
     $input = $this->_input->filter(array('redirect' => XenForo_Input::STRING, 'timestamp' => XenForo_Input::UINT, 'md5' => XenForo_Input::STRING));
     if (!empty($input['md5']) && !empty($input['timestamp']) && !empty($input['redirect'])) {
         $md5 = '';
         try {
             $md5 = bdApi_Crypt::decryptTypeOne($input['md5'], $input['timestamp']);
         } catch (XenForo_Exception $e) {
             if (XenForo_Application::debugMode()) {
                 $this->_response->setHeader('X-Api-Exception', $e->getMessage());
             }
         }
         if (!empty($md5) && $md5 === md5($input['redirect'])) {
             $this->_bdApi_redirect = $input['redirect'];
             return $input['redirect'];
         }
     }
     return parent::getDynamicRedirect($fallbackUrl, $useReferrer);
 }
Exemplo n.º 7
0
 public static function buildPublicLink($type, $data = null, array $extraParams = array(), $skipPrepend = false)
 {
     // the type MUST BE canonical:$type
     // NOTE: this is the opposite with api links
     if (strpos($type, 'full:') === 0) {
         // replace full: with canonical:
         $type = str_replace('full:', 'canonical:', $type);
     } elseif (strpos($type, 'canonical:') === false) {
         // enforce canonical:
         $type = 'canonical:' . $type;
     }
     $session = bdApi_Data_Helper_Core::safeGetSession();
     if (!empty($session)) {
         // auto appends locale param from session
         if (!isset($extraParams['locale'])) {
             $locale = $session->get('requestLocale');
             if (!empty($locale)) {
                 $timestamp = time() + 86400;
                 $extraParams['_apiLanguageId'] = sprintf('%s %s', $timestamp, bdApi_Crypt::encryptTypeOne($session->get('languageId'), $timestamp));
             }
         }
     }
     return parent::buildPublicLink($type, $data, $extraParams, $skipPrepend);
 }
Exemplo n.º 8
0
Arquivo: User.php Projeto: sushj/bdApi
 public function actionPutIndex()
 {
     $input = $this->_input->filter(array('password' => XenForo_Input::STRING, 'password_old' => XenForo_Input::STRING, 'password_algo' => XenForo_Input::STRING, 'user_email' => XenForo_Input::STRING, 'username' => XenForo_Input::STRING, 'primary_group_id' => XenForo_Input::UINT, 'secondary_group_ids' => array(XenForo_Input::UINT, 'array' => true), 'user_dob_day' => XenForo_Input::UINT, 'user_dob_month' => XenForo_Input::UINT, 'user_dob_year' => XenForo_Input::UINT, 'user_fields' => XenForo_Input::ARRAY_SIMPLE));
     $user = $this->_getUserOrError();
     $visitor = XenForo_Visitor::getInstance();
     $session = bdApi_Data_Helper_Core::safeGetSession();
     $isAdmin = $session->checkScope(bdApi_Model_OAuth2::SCOPE_MANAGE_SYSTEM) && $visitor->hasAdminPermission('user');
     $requiredAuth = 0;
     if (!empty($input['password'])) {
         $requiredAuth++;
     }
     if (!empty($input['user_email'])) {
         $requiredAuth++;
     }
     if ($requiredAuth > 0) {
         $isAuth = false;
         if ($isAdmin && $visitor['user_id'] != $user['user_id']) {
             $isAuth = true;
         } elseif (!empty($input['password_old'])) {
             $auth = $this->_getUserModel()->getUserAuthenticationObjectByUserId($user['user_id']);
             if (!empty($auth)) {
                 $passwordOld = bdApi_Crypt::decrypt($input['password_old'], $input['password_algo']);
                 if ($auth->hasPassword() && $auth->authenticate($user['user_id'], $passwordOld)) {
                     $isAuth = true;
                 }
             }
         }
         if (!$isAuth) {
             return $this->responseError(new XenForo_Phrase('bdapi_slash_users_requires_password_old'), 403);
         }
     }
     /* @var $writer XenForo_DataWriter_User */
     $writer = XenForo_DataWriter::create('XenForo_DataWriter_User');
     $writer->setExistingData($user, true);
     if ($isAdmin) {
         $writer->setOption(XenForo_DataWriter_User::OPTION_ADMIN_EDIT, true);
     }
     if (!empty($input['password'])) {
         $password = bdApi_Crypt::decrypt($input['password'], $input['password_algo']);
         $writer->setPassword($password, $password);
     }
     if (!empty($input['user_email'])) {
         $writer->set('email', $input['user_email']);
         if ($writer->isChanged('email') && XenForo_Application::getOptions()->get('registrationSetup', 'emailConfirmation') && !$isAdmin) {
             switch ($writer->get('user_state')) {
                 case 'moderated':
                 case 'email_confirm':
                     $writer->set('user_state', 'email_confirm');
                     break;
                 default:
                     $writer->set('user_state', 'email_confirm_edit');
             }
         }
     }
     if (!empty($input['username'])) {
         $writer->set('username', $input['username']);
         if ($writer->isChanged('username') && !$isAdmin) {
             return $this->responseError(new XenForo_Phrase('bdapi_slash_users_denied_username'), 403);
         }
     }
     if ($input['primary_group_id'] > 0) {
         $userGroups = $this->_getUserGroupModel()->getAllUserGroups();
         if (!isset($userGroups[$input['primary_group_id']])) {
             return $this->responseError(new XenForo_Phrase('requested_user_group_not_found'));
         }
         if (!empty($input['secondary_group_ids'])) {
             foreach ($input['secondary_group_ids'] as $secondaryGroupId) {
                 if (!isset($userGroups[$secondaryGroupId])) {
                     return $this->responseError(new XenForo_Phrase('requested_user_group_not_found'));
                 }
             }
         }
         $writer->set('user_group_id', $input['primary_group_id']);
         $writer->setSecondaryGroups($input['secondary_group_ids']);
     }
     if (!empty($input['user_dob_day']) && !empty($input['user_dob_month']) && !empty($input['user_dob_year'])) {
         $writer->set('dob_day', $input['user_dob_day']);
         $writer->set('dob_month', $input['user_dob_month']);
         $writer->set('dob_year', $input['user_dob_year']);
         $hasExistingDob = false;
         $hasExistingDob = $hasExistingDob || !!$writer->getExisting('dob_day');
         $hasExistingDob = $hasExistingDob || !!$writer->getExisting('dob_month');
         $hasExistingDob = $hasExistingDob || !!$writer->getExisting('dob_year');
         if ($hasExistingDob && ($writer->isChanged('dob_day') || $writer->isChanged('dob_month') || $writer->isChanged('dob_year')) && !$isAdmin) {
             // setting new dob is fine but changing dob requires admin permission
             return $this->responseError(new XenForo_Phrase('bdapi_slash_users_denied_dob'), 403);
         }
     }
     if (!empty($input['user_fields'])) {
         $profileFieldsInput = new XenForo_Input($input['user_fields']);
         $profileFields = $profileFieldsInput->filter(array('about' => XenForo_Input::STRING, 'homepage' => XenForo_Input::STRING, 'location' => XenForo_Input::STRING, 'occupation' => XenForo_Input::STRING));
         $writer->bulkSet($profileFields);
         $writer->setCustomFields($input['user_fields']);
     }
     $writer->preSave();
     if (!$isAdmin) {
         if ($writer->isChanged('user_group_id') || $writer->isChanged('secondary_group_ids')) {
             // this has to be checked here because `secondary_group_ids` only get set within preSave()
             return $this->responseError(new XenForo_Phrase('bdapi_slash_users_denied_user_group'), 403);
         }
     }
     $writer->save();
     $user = $writer->getMergedData();
     if ($writer->isChanged('email') && in_array($user['user_state'], array('email_confirm', 'email_confirm_edit'))) {
         /* @var $userConfirmationModel XenForo_Model_UserConfirmation */
         $userConfirmationModel = $this->getModelFromCache('XenForo_Model_UserConfirmation');
         $userConfirmationModel->sendEmailConfirmation($user);
     }
     return $this->responseMessage(new XenForo_Phrase('changes_saved'));
 }
Exemplo n.º 9
0
 public function actionPutIndex()
 {
     $user = $this->_getUserOrError();
     $visitor = XenForo_Visitor::getInstance();
     $input = $this->_input->filter(array('password_old' => XenForo_Input::STRING, 'password_algo' => XenForo_Input::STRING, 'user_email' => XenForo_Input::STRING, 'username' => XenForo_Input::STRING, 'password' => XenForo_Input::STRING, 'user_dob_day' => XenForo_Input::UINT, 'user_dob_month' => XenForo_Input::UINT, 'user_dob_year' => XenForo_Input::UINT));
     $session = bdApi_Data_Helper_Core::safeGetSession();
     $isAdmin = $session->checkScope(bdApi_Model_OAuth2::SCOPE_MANAGE_SYSTEM) && $visitor->hasAdminPermission('user');
     $isAuth = false;
     if ($isAdmin && $visitor['user_id'] != $user['user_id']) {
         $isAuth = true;
     } elseif (!empty($input['password_old'])) {
         $auth = $this->_getUserModel()->getUserAuthenticationObjectByUserId($user['user_id']);
         if (!empty($auth)) {
             $passwordOld = bdApi_Crypt::decrypt($input['password_old'], $input['password_algo']);
             if ($auth->hasPassword() && $auth->authenticate($user['user_id'], $passwordOld)) {
                 $isAuth = true;
             }
         }
     }
     if (!$isAuth) {
         return $this->responseNoPermission();
     }
     /* @var $writer XenForo_DataWriter_User */
     $writer = XenForo_DataWriter::create('XenForo_DataWriter_User');
     $writer->setExistingData($user, true);
     if (!empty($input['user_email'])) {
         $writer->set('email', $input['user_email']);
         if ($writer->isChanged('email') && XenForo_Application::getOptions()->get('registrationSetup', 'emailConfirmation') && !$isAdmin) {
             switch ($writer->get('user_state')) {
                 case 'moderated':
                 case 'email_confirm':
                     $writer->set('user_state', 'email_confirm');
                     break;
                 default:
                     $writer->set('user_state', 'email_confirm_edit');
             }
         }
     }
     if (!empty($input['username'])) {
         if (!$isAdmin) {
             return $this->responseNoPermission();
         }
         $writer->set('username', $input['username']);
     }
     if (!empty($input['password'])) {
         $password = bdApi_Crypt::decrypt($input['password'], $input['password_algo']);
         $writer->setPassword($password, $password);
     }
     if (!empty($input['user_dob_day']) && !empty($input['user_dob_month']) && !empty($input['user_dob_year'])) {
         $hasExistingDob = false;
         $hasExistingDob = $hasExistingDob || !!$writer->getExisting('dob_day');
         $hasExistingDob = $hasExistingDob || !!$writer->getExisting('dob_month');
         $hasExistingDob = $hasExistingDob || !!$writer->getExisting('dob_year');
         if ($hasExistingDob) {
             if (!$isAdmin) {
                 // changing dob requires admin permission
                 return $this->responseNoPermission();
             }
         } else {
             // new dob just needs auth
         }
         $writer->set('dob_day', $input['user_dob_day']);
         $writer->set('dob_month', $input['user_dob_month']);
         $writer->set('dob_year', $input['user_dob_year']);
     }
     if (!$writer->hasChanges()) {
         return $this->responseError(new XenForo_Phrase('error_occurred_or_request_stopped'), 400);
     }
     $writer->save();
     $user = $writer->getMergedData();
     if ($writer->isChanged('email') && in_array($user['user_state'], array('email_confirm', 'email_confirm_edit'))) {
         /* @var $userConfirmationModel XenForo_Model_UserConfirmation */
         $userConfirmationModel = $this->getModelFromCache('XenForo_Model_UserConfirmation');
         $userConfirmationModel->sendEmailConfirmation($user);
     }
     return $this->responseMessage(new XenForo_Phrase('changes_saved'));
 }
Exemplo n.º 10
0
 public function actionAuthorize()
 {
     /* @var $oauth2Model bdApi_Model_OAuth2 */
     $oauth2Model = $this->getModelFromCache('bdApi_Model_OAuth2');
     $authorizeParams = $this->_input->filter($oauth2Model->getAuthorizeParamsInputFilter());
     if ($this->_request->isPost()) {
         // allow user to deny some certain scopes
         // only when this is a POST request, this should keep us safe from some vectors
         // of attack
         $scopesIncluded = $this->_input->filterSingle('scopes_included', XenForo_Input::UINT);
         $scopes = $this->_input->filterSingle('scopes', XenForo_Input::ARRAY_SIMPLE);
         if (!empty($scopesIncluded)) {
             $authorizeParams['scope'] = bdApi_Template_Helper_Core::getInstance()->scopeJoin($scopes);
         }
     }
     $client = null;
     $clientIsAuto = false;
     if (empty($authorizeParams['client_id'])) {
         // try to get the first client of user if available
         $visitorClients = $this->_bdApi_getClientModel()->getClients(array('user_id' => XenForo_Visitor::getUserId()), array('limit' => 1));
         if (!empty($visitorClients)) {
             $randClientId = array_rand($visitorClients, 1);
             $client = $visitorClients[$randClientId];
             $clientIsAuto = true;
             $authorizeParams['client_id'] = $client['client_id'];
             // auto assign at least the READ scope
             if (empty($authorizeParams['scope'])) {
                 $authorizeParams['scope'] = bdApi_Model_OAuth2::SCOPE_READ;
             }
             // reset the redirect uri to prevent security issue
             $authorizeParams['redirect_uri'] = '';
             // force to use implicit authentication flow2
             $authorizeParams['response_type'] = 'token';
         }
     } else {
         $client = $oauth2Model->getClientModel()->getClientById($authorizeParams['client_id']);
     }
     if (empty($client)) {
         if (XenForo_Visitor::getInstance()->hasPermission('general', 'bdApi_clientNew')) {
             return $this->responseError(new XenForo_Phrase('bdapi_authorize_no_client_create_one_question', array('link' => XenForo_Link::buildPublicLink('account/api/client-add'))), 404);
         }
         return $this->responseError(new XenForo_Phrase('bdapi_authorize_error_client_x_not_found', array('client' => $authorizeParams['client_id'])), 404);
     }
     // sondh@2013-03-19
     // this is a non-standard implementation: bypass confirmation dialog if the
     // client has appropriate option set
     $bypassConfirmation = false;
     if ($oauth2Model->getClientModel()->canAutoAuthorize($client, $authorizeParams['scope'])) {
         $bypassConfirmation = true;
     }
     // sondh@2015-09-28
     // bypass confirmation if user logged in to authorize
     // this is secured by checking our encrypted time-expiring hash
     $hashInput = $this->_input->filter(array('hash' => XenForo_Input::STRING, 'timestamp' => XenForo_Input::UINT));
     if (!empty($hashInput['hash']) && !empty($hashInput['timestamp'])) {
         try {
             if (bdApi_Crypt::decryptTypeOne($hashInput['hash'], $hashInput['timestamp'])) {
                 $bypassConfirmation = true;
             }
         } catch (XenForo_Exception $e) {
             if (XenForo_Application::debugMode()) {
                 $this->_response->setHeader('X-Api-Exception', $e->getMessage());
             }
         }
     }
     // sondh@2014-09-26
     // bypass confirmation if all requested scopes have been granted at some point
     // in old version of this add-on, it checked for scope from active tokens
     // from now on, we look for all scopes (no expiration) for better user experience
     // if a token expires, it should not invalidate all user's choices
     $userScopes = $oauth2Model->getUserScopeModel()->getUserScopes($client['client_id'], XenForo_Visitor::getUserId());
     $paramScopes = bdApi_Template_Helper_Core::getInstance()->scopeSplit($authorizeParams['scope']);
     $paramScopesNew = array();
     foreach ($paramScopes as $paramScope) {
         if (!isset($userScopes[$paramScope])) {
             $paramScopesNew[] = $paramScope;
         }
     }
     if (empty($paramScopesNew)) {
         $bypassConfirmation = true;
     } else {
         $authorizeParams['scope'] = bdApi_Template_Helper_Core::getInstance()->scopeJoin($paramScopesNew);
     }
     // sondh@2015-09-28
     // disable bypassing confirmation for testing purpose
     if ($clientIsAuto) {
         $bypassConfirmation = false;
     }
     $response = $oauth2Model->getServer()->actionOauthAuthorize1($this, $authorizeParams);
     if (is_object($response) && $response instanceof XenForo_ControllerResponse_Abstract) {
         return $response;
     }
     if ($this->_request->isPost() || $bypassConfirmation) {
         $accept = $this->_input->filterSingle('accept', XenForo_Input::STRING);
         $accepted = !!$accept;
         if ($bypassConfirmation) {
             // sondh@2013-03-19
             // of course if the dialog was bypassed, $accepted should be true
             $accepted = true;
         }
         if ($accepted) {
             // sondh@2014-09-26
             // get all up to date user scopes and include in the new token
             // that means client only need to ask for a scope once and they will always have
             // that scope in future authorizations, even if they ask for less scope!
             // making it easy for client dev, they don't need to track whether they requested
             // a scope before. Just check the most recent token for that information.
             $paramScopes = bdApi_Template_Helper_Core::getInstance()->scopeSplit($authorizeParams['scope']);
             foreach ($userScopes as $userScope => $userScopeInfo) {
                 if (!in_array($userScope, $paramScopes, true)) {
                     $paramScopes[] = $userScope;
                 }
             }
             $paramScopes = array_unique($paramScopes);
             asort($paramScopes);
             $authorizeParams['scope'] = bdApi_Template_Helper_Core::getInstance()->scopeJoin($paramScopes);
         }
         return $oauth2Model->getServer()->actionOauthAuthorize2($this, $authorizeParams, $accepted, XenForo_Visitor::getUserId());
     } else {
         $viewParams = array('client' => $client, 'authorizeParams' => $authorizeParams, 'clientIsAuto' => $clientIsAuto);
         return $this->_getWrapper('account', 'api', $this->responseView('bdApi_ViewPublic_Account_Authorize', 'bdapi_account_authorize', $viewParams));
     }
 }
Exemplo n.º 11
0
 public function actionPostTokenGoogle()
 {
     $client = $this->_getClientOrError();
     /* @var $userExternalModel XenForo_Model_UserExternal */
     $userExternalModel = $this->getModelFromCache('XenForo_Model_UserExternal');
     $googleToken = $this->_input->filterSingle('google_token', XenForo_Input::STRING);
     $httpClient = XenForo_Helper_Http::getClient('https://www.googleapis.com/plus/v1/people/me');
     $httpClient->setParameterGet('access_token', $googleToken);
     $response = $httpClient->request('GET');
     $googleUser = json_decode($response->getBody(), true);
     if (empty($googleUser['id'])) {
         return $this->responseError(new XenForo_Phrase('bdapi_invalid_google_token'));
     }
     $googleAssoc = $userExternalModel->getExternalAuthAssociation('google', $googleUser['id']);
     if (empty($googleAssoc)) {
         $userData = array();
         if (!empty($googleUser['displayName'])) {
             $testDw = XenForo_DataWriter::create('XenForo_DataWriter_User');
             $testDw->set('username', $googleUser['displayName']);
             if (!$testDw->hasErrors()) {
                 // good username
                 $userData['username'] = $googleUser['displayName'];
             }
         }
         if (!empty($googleUser['emails'])) {
             foreach ($googleUser['emails'] as $googleEmail) {
                 $userData['user_email'] = $googleEmail['value'];
                 break;
             }
         }
         if (!empty($googleUser['birthday'])) {
             if (preg_match('#^(?<year>\\d+)-(?<month>\\d+)-(?<day>\\d+)$#', $googleUser['birthday'], $birthdayMatches)) {
                 $userData['user_dob_year'] = $birthdayMatches['year'];
                 $userData['user_dob_month'] = $birthdayMatches['month'];
                 $userData['user_dob_day'] = $birthdayMatches['day'];
             }
         }
         $extraData = array('external_provider' => 'google', 'external_provider_key' => $googleUser['id']);
         if (!empty($userData['user_email'])) {
             $extraData['user_email'] = $userData['user_email'];
         }
         $extraData = serialize($extraData);
         $extraTimestamp = time() + bdApi_Option::get('refreshTokenTTLDays') * 86400;
         $userData += array('extra_data' => bdApi_Crypt::encryptTypeOne($extraData, $extraTimestamp), 'extra_timestamp' => $extraTimestamp);
         $data = array('status' => 'ok', 'message' => new XenForo_Phrase('bdapi_no_google_association_found'), 'user_data' => $userData);
         return $this->responseData('bdApi_ViewApi_OAuth_TokenGoogle_NoAssoc', $data);
     }
     return $this->_actionPostTokenNonStandard($client, $googleAssoc['user_id']);
 }