diff --git a/src/applications/auth/controller/oauthregistration/PhabricatorOAuthDefaultRegistrationController.php b/src/applications/auth/controller/oauthregistration/PhabricatorOAuthDefaultRegistrationController.php index 9c8c157690..3f3c114d9d 100644 --- a/src/applications/auth/controller/oauthregistration/PhabricatorOAuthDefaultRegistrationController.php +++ b/src/applications/auth/controller/oauthregistration/PhabricatorOAuthDefaultRegistrationController.php @@ -1,230 +1,239 @@ getOAuthProvider(); $oauth_info = $this->getOAuthInfo(); $request = $this->getRequest(); $errors = array(); $e_username = true; $e_email = true; $e_realname = true; $user = new PhabricatorUser(); $user->setUsername($provider->retrieveUserAccountName()); $user->setRealName($provider->retrieveUserRealName()); $new_email = $provider->retrieveUserEmail(); if ($new_email) { // If the user's OAuth provider account has an email address but the // email address domain is not allowed by the Phabricator configuration, // we just pretend the provider did not supply an address. // // For instance, if the user uses Google OAuth and their Google address // is "joe@personal.com" but Phabricator is configured to require users // use "@company.com" addresses, we show a prompt below and tell the user // to provide their "@company.com" address. They can still use the OAuth // account to login, they just need to associate their account with an // allowed address. // // If the OAuth address is fine, we just use it and don't prompt the user. if (!PhabricatorUserEmail::isAllowedAddress($new_email)) { $new_email = null; } } $show_email_input = ($new_email === null); if ($request->isFormPost()) { $user->setUsername($request->getStr('username')); $username = $user->getUsername(); if (!strlen($user->getUsername())) { $e_username = 'Required'; $errors[] = 'Username is required.'; } else if (!PhabricatorUser::validateUsername($username)) { $e_username = 'Invalid'; $errors[] = PhabricatorUser::describeValidUsername(); } else { $e_username = null; } if (!$new_email) { $new_email = trim($request->getStr('email')); if (!$new_email) { $e_email = 'Required'; $errors[] = 'Email is required.'; } else { $e_email = null; } } if ($new_email) { $email_ok = PhabricatorUserEmail::isAllowedAddress($new_email); if (!$email_ok) { $e_email = 'Invalid'; $errors[] = PhabricatorUserEmail::describeAllowedAddresses(); } } if (!strlen($user->getRealName())) { $user->setRealName($request->getStr('realname')); if (!strlen($user->getRealName())) { $e_realname = 'Required'; $errors[] = 'Real name is required.'; } else { $e_realname = null; } } if (!$errors) { $image = $provider->retrieveUserProfileImage(); if ($image) { $file = PhabricatorFile::newFromFileData( $image, array( 'name' => $provider->getProviderKey().'-profile.jpg', 'authorPHID' => $user->getPHID(), )); - $user->setProfileImagePHID($file->getPHID()); + $xformer = new PhabricatorImageTransformer(); + + // Resize OAuth image to a reasonable size + $small_xformed = $xformer->executeProfileTransform( + $file, + $width = 50, + $min_height = 50, + $max_height = 50); + + $user->setProfileImagePHID($small_xformed->getPHID()); } try { // NOTE: We don't verify OAuth email addresses by default because // OAuth providers might associate email addresses with accounts that // haven't actually verified they own them. We could selectively // auto-verify some providers that we trust here, but the stakes for // verifying an email address are high because having a corporate // address at a company is sometimes the key to the castle. $email_obj = id(new PhabricatorUserEmail()) ->setAddress($new_email) ->setIsVerified(0); id(new PhabricatorUserEditor()) ->setActor($user) ->createNewUser($user, $email_obj); $oauth_info->setUserID($user->getID()); $oauth_info->save(); $session_key = $user->establishSession('web'); $request->setCookie('phusr', $user->getUsername()); $request->setCookie('phsid', $session_key); $email_obj->sendVerificationEmail($user); return id(new AphrontRedirectResponse())->setURI('/'); } catch (AphrontQueryDuplicateKeyException $exception) { $same_username = id(new PhabricatorUser())->loadOneWhere( 'userName = %s', $user->getUserName()); $same_email = id(new PhabricatorUserEmail())->loadOneWhere( 'address = %s', $new_email); if ($same_username) { $e_username = 'Duplicate'; $errors[] = 'That username or email is not unique.'; } else if ($same_email) { $e_email = 'Duplicate'; $errors[] = 'That email is not unique.'; } else { throw $exception; } } } } $error_view = null; if ($errors) { $error_view = new AphrontErrorView(); $error_view->setTitle('Registration Failed'); $error_view->setErrors($errors); } // Strip the URI down to the path, because otherwise we'll trigger // external CSRF protection (by having a protocol in the form "action") // and generate a form with no CSRF token. $action_uri = new PhutilURI($provider->getRedirectURI()); $action_path = $action_uri->getPath(); $form = new AphrontFormView(); $form ->addHiddenInput('confirm_token', $provider->getAccessToken()) ->addHiddenInput('expires', $oauth_info->getTokenExpires()) ->addHiddenInput('state', $this->getOAuthState()) ->setUser($request->getUser()) ->setAction($action_path) ->appendChild( id(new AphrontFormTextControl()) ->setLabel('Username') ->setName('username') ->setValue($user->getUsername()) ->setError($e_username)); if ($show_email_input) { $form->appendChild( id(new AphrontFormTextControl()) ->setLabel('Email') ->setName('email') ->setValue($request->getStr('email')) ->setCaption(PhabricatorUserEmail::describeAllowedAddresses()) ->setError($e_email)); } if ($provider->retrieveUserRealName() === null) { $form->appendChild( id(new AphrontFormTextControl()) ->setLabel('Real Name') ->setName('realname') ->setValue($request->getStr('realname')) ->setError($e_realname)); } $form ->appendChild( id(new AphrontFormSubmitControl()) ->setValue('Create Account')); $panel = new AphrontPanelView(); $panel->setHeader('Create New Account'); $panel->setWidth(AphrontPanelView::WIDTH_FORM); $panel->appendChild($form); return $this->buildStandardPageResponse( array( $error_view, $panel, ), array( 'title' => 'Create New Account', )); } } diff --git a/src/applications/people/controller/settings/panels/PhabricatorUserOAuthSettingsPanelController.php b/src/applications/people/controller/settings/panels/PhabricatorUserOAuthSettingsPanelController.php index 8f8dbf8fd4..031112b9cd 100644 --- a/src/applications/people/controller/settings/panels/PhabricatorUserOAuthSettingsPanelController.php +++ b/src/applications/people/controller/settings/panels/PhabricatorUserOAuthSettingsPanelController.php @@ -1,245 +1,255 @@ provider = $oauth_provider; return $this; } private function prepareAuthForm(AphrontFormView $form) { $provider = $this->provider; $auth_uri = $provider->getAuthURI(); $client_id = $provider->getClientID(); $redirect_uri = $provider->getRedirectURI(); $minimum_scope = $provider->getMinimumScope(); $form ->setAction($auth_uri) ->setMethod('GET') ->addHiddenInput('redirect_uri', $redirect_uri) ->addHiddenInput('client_id', $client_id) ->addHiddenInput('scope', $minimum_scope); foreach ($provider->getExtraAuthParameters() as $key => $value) { $form->addHiddenInput($key, $value); } return $form; } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $provider = $this->provider; $notice = null; $provider_name = $provider->getProviderName(); $provider_key = $provider->getProviderKey(); $oauth_info = id(new PhabricatorUserOAuthInfo())->loadOneWhere( 'userID = %d AND oauthProvider = %s', $user->getID(), $provider->getProviderKey()); if ($request->isFormPost() && $oauth_info) { $notice = $this->refreshProfileImage($oauth_info); } $form = new AphrontFormView(); $form->setUser($user); $forms = array(); $forms[] = $form; if (!$oauth_info) { $form ->appendChild( '

There is currently no '. phutil_escape_html($provider_name).' account linked to your '. 'Phabricator account. You can link an account, which will allow you '. 'to use it to log into Phabricator.

'); $this->prepareAuthForm($form); $form ->appendChild( id(new AphrontFormSubmitControl()) ->setValue('Link '.$provider_name." Account \xC2\xBB")); } else { $expires = $oauth_info->getTokenExpires(); $form ->appendChild( '

Your account is linked with '. 'a '.phutil_escape_html($provider_name).' account. You may use your '. phutil_escape_html($provider_name).' credentials to log into '. 'Phabricator.

') ->appendChild( id(new AphrontFormStaticControl()) ->setLabel($provider_name.' ID') ->setValue($oauth_info->getOAuthUID()) ) ->appendChild( id(new AphrontFormStaticControl()) ->setLabel($provider_name.' Name') ->setValue($oauth_info->getAccountName()) ) ->appendChild( id(new AphrontFormStaticControl()) ->setLabel($provider_name.' URI') ->setValue($oauth_info->getAccountURI()) ); if (!$expires || $expires > time()) { $form->appendChild( id(new AphrontFormSubmitControl()) ->setValue('Refresh Profile Image from '.$provider_name) ); } if (!$provider->isProviderLinkPermanent()) { $unlink = 'Unlink '.$provider_name.' Account'; $unlink_form = new AphrontFormView(); $unlink_form ->setUser($user) ->appendChild( '

You may unlink this account '. 'from your '.phutil_escape_html($provider_name).' account. This '. 'will prevent you from logging in with your '. phutil_escape_html($provider_name).' credentials.

') ->appendChild( id(new AphrontFormSubmitControl()) ->addCancelButton('/oauth/'.$provider_key.'/unlink/', $unlink)); $forms['Unlink Account'] = $unlink_form; } if ($expires) { if ($expires <= time()) { $expires_text = "Expired"; } else { $expires_text = phabricator_datetime($expires, $user); } } else { $expires_text = 'No Information Available'; } $scope = $oauth_info->getTokenScope(); if (!$scope) { $scope = 'No Information Available'; } $status = $oauth_info->getTokenStatus(); $status = PhabricatorUserOAuthInfo::getReadableTokenStatus($status); $token_form = new AphrontFormView(); $token_form ->setUser($user) ->appendChild( '

insert rap about tokens

') ->appendChild( id(new AphrontFormStaticControl()) ->setLabel('Token Status') ->setValue($status)) ->appendChild( id(new AphrontFormStaticControl()) ->setLabel('Expires') ->setValue($expires_text)) ->appendChild( id(new AphrontFormStaticControl()) ->setLabel('Scope') ->setValue($scope)); if ($expires <= time()) { $this->prepareAuthForm($token_form); $token_form ->appendChild( id(new AphrontFormSubmitControl()) ->setValue('Refresh '.$provider_name.' Token') ); } $forms['Account Token Information'] = $token_form; } $panel = new AphrontPanelView(); $panel->setHeader($provider_name.' Account Settings'); $panel->setWidth(AphrontPanelView::WIDTH_FORM); foreach ($forms as $name => $form) { if ($name) { $panel->appendChild('

'.$name.'


'); } $panel->appendChild($form); } return id(new AphrontNullView()) ->appendChild( array( $notice, $panel, )); } private function refreshProfileImage(PhabricatorUserOAuthInfo $oauth_info) { $user = $this->getRequest()->getUser(); $provider = $this->provider; $error = false; $userinfo_uri = new PhutilURI($provider->getUserInfoURI()); $token = $oauth_info->getToken(); try { $userinfo_uri->setQueryParam('access_token', $token); $user_data = HTTPSFuture::loadContent($userinfo_uri); $provider->setUserData($user_data); $provider->setAccessToken($token); $image = $provider->retrieveUserProfileImage(); if ($image) { $file = PhabricatorFile::newFromFileData( $image, array( 'name' => $provider->getProviderKey().'-profile.jpg', 'authorPHID' => $user->getPHID(), )); - $user->setProfileImagePHID($file->getPHID()); + + $xformer = new PhabricatorImageTransformer(); + + // Resize OAuth image to a reasonable size + $small_xformed = $xformer->executeProfileTransform( + $file, + $width = 50, + $min_height = 50, + $max_height = 50); + + $user->setProfileImagePHID($small_xformed->getPHID()); $user->save(); } else { $error = 'Unable to retrieve image.'; } } catch (Exception $e) { if ($e instanceof PhabricatorOAuthProviderException) { $error = sprintf('Unable to retrieve image from %s', $provider->getProviderName()); } else { $error = 'Unable to save image.'; } } $notice = new AphrontErrorView(); if ($error) { $notice ->setTitle('Error Refreshing Profile Picture') ->setErrors(array($error)); } else { $notice ->setSeverity(AphrontErrorView::SEVERITY_NOTICE) ->setTitle('Successfully Refreshed Profile Picture'); } return $notice; } }