public function isUsableForLogin()
 {
     $key = $this->getProviderKey();
     $provider = PhabricatorAuthProvider::getEnabledProviderByKey($key);
     if (!$provider) {
         return false;
     }
     if (!$provider->shouldAllowLogin()) {
         return false;
     }
     return true;
 }
 private function init($viewer, $repository)
 {
     $repo_uri = $repository->getRemoteURIObject();
     $repo_domain = $repo_uri->getDomain();
     $this->account = id(new PhabricatorExternalAccountQuery())->setViewer($viewer)->withUserPHIDs(array($viewer->getPHID()))->withAccountTypes(array('github'))->withAccountDomains(array($repo_domain))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne();
     if (!$this->account) {
         throw new Exception(pht('No matching GitHub account found for %s.', $repo_domain));
     }
     $this->provider = PhabricatorAuthProvider::getEnabledProviderByKey($this->account->getProviderKey());
     if (!$this->provider) {
         throw new Exception(pht('GitHub provider for %s is not enabled.', $repo_domain));
     }
 }
 private function renderConfirmDialog()
 {
     $provider_key = $this->providerKey;
     $provider = PhabricatorAuthProvider::getEnabledProviderByKey($provider_key);
     if ($provider) {
         $title = pht('Unlink "%s" Account?', $provider->getProviderName());
         $body = pht('You will no longer be able to use your %s account to ' . 'log in to Phabricator.', $provider->getProviderName());
     } else {
         $title = pht('Unlink Account?');
         $body = pht('You will no longer be able to use this account to log in ' . 'to Phabricator.');
     }
     $dialog = id(new AphrontDialogView())->setUser($this->getRequest()->getUser())->setTitle($title)->appendParagraph($body)->appendParagraph(pht('Note: Unlinking an authentication provider will terminate any ' . 'other active login sessions.'))->addSubmitButton(pht('Unlink Account'))->addCancelButton($this->getDoneURI());
     return id(new AphrontDialogResponse())->setDialog($dialog);
 }
 public function handleRequest(AphrontRequest $request)
 {
     $viewer = $this->getViewer();
     $id = $request->getURIData('id');
     $user = id(new PhabricatorPeopleQuery())->setViewer($viewer)->withIDs(array($id))->needProfileImage(true)->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne();
     if (!$user) {
         return new Aphront404Response();
     }
     $this->setUser($user);
     $done_uri = $this->getApplicationURI("manage/{$id}/");
     $supported_formats = PhabricatorFile::getTransformableImageFormats();
     $e_file = true;
     $errors = array();
     if ($request->isFormPost()) {
         $phid = $request->getStr('phid');
         $is_default = false;
         if ($phid == PhabricatorPHIDConstants::PHID_VOID) {
             $phid = null;
             $is_default = true;
         } else {
             if ($phid) {
                 $file = id(new PhabricatorFileQuery())->setViewer($viewer)->withPHIDs(array($phid))->executeOne();
             } else {
                 if ($request->getFileExists('picture')) {
                     $file = PhabricatorFile::newFromPHPUpload($_FILES['picture'], array('authorPHID' => $viewer->getPHID(), 'canCDN' => true));
                 } else {
                     $e_file = pht('Required');
                     $errors[] = pht('You must choose a file when uploading a new profile picture.');
                 }
             }
         }
         if (!$errors && !$is_default) {
             if (!$file->isTransformableImage()) {
                 $e_file = pht('Not Supported');
                 $errors[] = pht('This server only supports these image formats: %s.', implode(', ', $supported_formats));
             } else {
                 $xform = PhabricatorFileTransform::getTransformByKey(PhabricatorFileThumbnailTransform::TRANSFORM_PROFILE);
                 $xformed = $xform->executeTransform($file);
             }
         }
         if (!$errors) {
             if ($is_default) {
                 $user->setProfileImagePHID(null);
             } else {
                 $user->setProfileImagePHID($xformed->getPHID());
                 $xformed->attachToObject($user->getPHID());
             }
             $user->save();
             return id(new AphrontRedirectResponse())->setURI($done_uri);
         }
     }
     $title = pht('Edit Profile Picture');
     $form = id(new PHUIFormLayoutView())->setUser($viewer);
     $default_image = PhabricatorFile::loadBuiltin($viewer, 'profile.png');
     $images = array();
     $current = $user->getProfileImagePHID();
     $has_current = false;
     if ($current) {
         $files = id(new PhabricatorFileQuery())->setViewer($viewer)->withPHIDs(array($current))->execute();
         if ($files) {
             $file = head($files);
             if ($file->isTransformableImage()) {
                 $has_current = true;
                 $images[$current] = array('uri' => $file->getBestURI(), 'tip' => pht('Current Picture'));
             }
         }
     }
     $builtins = array('user1.png', 'user2.png', 'user3.png', 'user4.png', 'user5.png', 'user6.png', 'user7.png', 'user8.png', 'user9.png');
     foreach ($builtins as $builtin) {
         $file = PhabricatorFile::loadBuiltin($viewer, $builtin);
         $images[$file->getPHID()] = array('uri' => $file->getBestURI(), 'tip' => pht('Builtin Image'));
     }
     // Try to add external account images for any associated external accounts.
     $accounts = id(new PhabricatorExternalAccountQuery())->setViewer($viewer)->withUserPHIDs(array($user->getPHID()))->needImages(true)->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->execute();
     foreach ($accounts as $account) {
         $file = $account->getProfileImageFile();
         if ($account->getProfileImagePHID() != $file->getPHID()) {
             // This is a default image, just skip it.
             continue;
         }
         $provider = PhabricatorAuthProvider::getEnabledProviderByKey($account->getProviderKey());
         if ($provider) {
             $tip = pht('Picture From %s', $provider->getProviderName());
         } else {
             $tip = pht('Picture From External Account');
         }
         if ($file->isTransformableImage()) {
             $images[$file->getPHID()] = array('uri' => $file->getBestURI(), 'tip' => $tip);
         }
     }
     $images[PhabricatorPHIDConstants::PHID_VOID] = array('uri' => $default_image->getBestURI(), 'tip' => pht('Default Picture'));
     require_celerity_resource('people-profile-css');
     Javelin::initBehavior('phabricator-tooltips', array());
     $buttons = array();
     foreach ($images as $phid => $spec) {
         $button = javelin_tag('button', array('class' => 'grey profile-image-button', 'sigil' => 'has-tooltip', 'meta' => array('tip' => $spec['tip'], 'size' => 300)), phutil_tag('img', array('height' => 50, 'width' => 50, 'src' => $spec['uri'])));
         $button = array(phutil_tag('input', array('type' => 'hidden', 'name' => 'phid', 'value' => $phid)), $button);
         $button = phabricator_form($viewer, array('class' => 'profile-image-form', 'method' => 'POST'), $button);
         $buttons[] = $button;
     }
     if ($has_current) {
         $form->appendChild(id(new AphrontFormMarkupControl())->setLabel(pht('Current Picture'))->setValue(array_shift($buttons)));
     }
     $form->appendChild(id(new AphrontFormMarkupControl())->setLabel(pht('Use Picture'))->setValue($buttons));
     $form_box = id(new PHUIObjectBoxView())->setHeaderText($title)->setFormErrors($errors)->setForm($form);
     $upload_form = id(new AphrontFormView())->setUser($viewer)->setEncType('multipart/form-data')->appendChild(id(new AphrontFormFileControl())->setName('picture')->setLabel(pht('Upload Picture'))->setError($e_file)->setCaption(pht('Supported formats: %s', implode(', ', $supported_formats))))->appendChild(id(new AphrontFormSubmitControl())->addCancelButton($done_uri)->setValue(pht('Upload Picture')));
     $upload_box = id(new PHUIObjectBoxView())->setHeaderText(pht('Upload New Picture'))->setForm($upload_form);
     $crumbs = $this->buildApplicationCrumbs();
     $crumbs->addTextCrumb(pht('Edit Profile Picture'));
     return $this->newPage()->setTitle($title)->setCrumbs($crumbs)->appendChild(array($form_box, $upload_box));
 }
 protected function loadAccountForRegistrationOrLinking($account_key)
 {
     $request = $this->getRequest();
     $viewer = $request->getUser();
     $account = null;
     $provider = null;
     $response = null;
     if (!$account_key) {
         $response = $this->renderError(pht('Request did not include account key.'));
         return array($account, $provider, $response);
     }
     // NOTE: We're using the omnipotent user because the actual user may not
     // be logged in yet, and because we want to tailor an error message to
     // distinguish between "not usable" and "does not exist". We do explicit
     // checks later on to make sure this account is valid for the intended
     // operation. This requires edit permission for completeness and consistency
     // but it won't actually be meaningfully checked because we're using the
     // ominpotent user.
     $account = id(new PhabricatorExternalAccountQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withAccountSecrets(array($account_key))->needImages(true)->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne();
     if (!$account) {
         $response = $this->renderError(pht('No valid linkable account.'));
         return array($account, $provider, $response);
     }
     if ($account->getUserPHID()) {
         if ($account->getUserPHID() != $viewer->getPHID()) {
             $response = $this->renderError(pht('The account you are attempting to register or link is already ' . 'linked to another user.'));
         } else {
             $response = $this->renderError(pht('The account you are attempting to link is already linked ' . 'to your account.'));
         }
         return array($account, $provider, $response);
     }
     $registration_key = $request->getCookie(PhabricatorCookies::COOKIE_REGISTRATION);
     // NOTE: This registration key check is not strictly necessary, because
     // we're only creating new accounts, not linking existing accounts. It
     // might be more hassle than it is worth, especially for email.
     //
     // The attack this prevents is getting to the registration screen, then
     // copy/pasting the URL and getting someone else to click it and complete
     // the process. They end up with an account bound to credentials you
     // control. This doesn't really let you do anything meaningful, though,
     // since you could have simply completed the process yourself.
     if (!$registration_key) {
         $response = $this->renderError(pht('Your browser did not submit a registration key with the request. ' . 'You must use the same browser to begin and complete registration. ' . 'Check that cookies are enabled and try again.'));
         return array($account, $provider, $response);
     }
     // We store the digest of the key rather than the key itself to prevent a
     // theoretical attacker with read-only access to the database from
     // hijacking registration sessions.
     $actual = $account->getProperty('registrationKey');
     $expect = PhabricatorHash::digest($registration_key);
     if ($actual !== $expect) {
         $response = $this->renderError(pht('Your browser submitted a different registration key than the one ' . 'associated with this account. You may need to clear your cookies.'));
         return array($account, $provider, $response);
     }
     $other_account = id(new PhabricatorExternalAccount())->loadAllWhere('accountType = %s AND accountDomain = %s AND accountID = %s
     AND id != %d', $account->getAccountType(), $account->getAccountDomain(), $account->getAccountID(), $account->getID());
     if ($other_account) {
         $response = $this->renderError(pht('The account you are attempting to register with already belongs ' . 'to another user.'));
         return array($account, $provider, $response);
     }
     $provider = PhabricatorAuthProvider::getEnabledProviderByKey($account->getProviderKey());
     if (!$provider) {
         $response = $this->renderError(pht('The account you are attempting to register with uses a nonexistent ' . 'or disabled authentication provider (with key "%s"). An ' . 'administrator may have recently disabled this provider.', $account->getProviderKey()));
         return array($account, $provider, $response);
     }
     return array($account, $provider, null);
 }
 public function handleRequest(AphrontRequest $request)
 {
     $viewer = $this->getViewer();
     $action = $request->getURIData('action');
     $provider_key = $request->getURIData('pkey');
     $provider = PhabricatorAuthProvider::getEnabledProviderByKey($provider_key);
     if (!$provider) {
         return new Aphront404Response();
     }
     switch ($action) {
         case 'link':
             if (!$provider->shouldAllowAccountLink()) {
                 return $this->renderErrorPage(pht('Account Not Linkable'), array(pht('This provider is not configured to allow linking.')));
             }
             break;
         case 'refresh':
             if (!$provider->shouldAllowAccountRefresh()) {
                 return $this->renderErrorPage(pht('Account Not Refreshable'), array(pht('This provider does not allow refreshing.')));
             }
             break;
         default:
             return new Aphront400Response();
     }
     $account = id(new PhabricatorExternalAccount())->loadOneWhere('accountType = %s AND accountDomain = %s AND userPHID = %s', $provider->getProviderType(), $provider->getProviderDomain(), $viewer->getPHID());
     switch ($action) {
         case 'link':
             if ($account) {
                 return $this->renderErrorPage(pht('Account Already Linked'), array(pht('Your Phabricator account is already linked to an external ' . 'account for this provider.')));
             }
             break;
         case 'refresh':
             if (!$account) {
                 return $this->renderErrorPage(pht('No Account Linked'), array(pht('You do not have a linked account on this provider, and thus ' . 'can not refresh it.')));
             }
             break;
         default:
             return new Aphront400Response();
     }
     $panel_uri = '/settings/panel/external/';
     PhabricatorCookies::setClientIDCookie($request);
     switch ($action) {
         case 'link':
             id(new PhabricatorAuthSessionEngine())->requireHighSecuritySession($viewer, $request, $panel_uri);
             $form = $provider->buildLinkForm($this);
             break;
         case 'refresh':
             $form = $provider->buildRefreshForm($this);
             break;
         default:
             return new Aphront400Response();
     }
     if ($provider->isLoginFormAButton()) {
         require_celerity_resource('auth-css');
         $form = phutil_tag('div', array('class' => 'phabricator-link-button pl'), $form);
     }
     switch ($action) {
         case 'link':
             $name = pht('Link Account');
             $title = pht('Link %s Account', $provider->getProviderName());
             break;
         case 'refresh':
             $name = pht('Refresh Account');
             $title = pht('Refresh %s Account', $provider->getProviderName());
             break;
         default:
             return new Aphront400Response();
     }
     $crumbs = $this->buildApplicationCrumbs();
     $crumbs->addTextCrumb(pht('Link Account'), $panel_uri);
     $crumbs->addTextCrumb($provider->getProviderName($name));
     return $this->buildApplicationPage(array($crumbs, $form), array('title' => $title));
 }
 private function loadProvider()
 {
     $provider = PhabricatorAuthProvider::getEnabledProviderByKey($this->providerKey);
     if (!$provider) {
         return $this->renderError(pht('The account you are attempting to login with uses a nonexistent ' . 'or disabled authentication provider (with key "%s"). An ' . 'administrator may have recently disabled this provider.', $this->providerKey));
     }
     $this->provider = $provider;
     return null;
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $viewer = $request->getUser();
     $user = id(new PhabricatorPeopleQuery())->setViewer($viewer)->withIDs(array($this->id))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne();
     if (!$user) {
         return new Aphront404Response();
     }
     $profile_uri = '/p/' . $user->getUsername() . '/';
     $supported_formats = PhabricatorFile::getTransformableImageFormats();
     $e_file = true;
     $errors = array();
     if ($request->isFormPost()) {
         $phid = $request->getStr('phid');
         $is_default = false;
         if ($phid == PhabricatorPHIDConstants::PHID_VOID) {
             $phid = null;
             $is_default = true;
         } else {
             if ($phid) {
                 $file = id(new PhabricatorFileQuery())->setViewer($viewer)->withPHIDs(array($phid))->executeOne();
             } else {
                 if ($request->getFileExists('picture')) {
                     $file = PhabricatorFile::newFromPHPUpload($_FILES['picture'], array('authorPHID' => $viewer->getPHID(), 'canCDN' => true));
                 } else {
                     $e_file = pht('Required');
                     $errors[] = pht('You must choose a file when uploading a new profile picture.');
                 }
             }
         }
         if (!$errors && !$is_default) {
             if (!$file->isTransformableImage()) {
                 $e_file = pht('Not Supported');
                 $errors[] = pht('This server only supports these image formats: %s.', implode(', ', $supported_formats));
             } else {
                 $xformer = new PhabricatorImageTransformer();
                 $xformed = $xformer->executeProfileTransform($file, $width = 50, $min_height = 50, $max_height = 50);
             }
         }
         if (!$errors) {
             if ($is_default) {
                 $user->setProfileImagePHID(null);
             } else {
                 $user->setProfileImagePHID($xformed->getPHID());
                 $xformed->attachToObject($user->getPHID());
             }
             $user->save();
             return id(new AphrontRedirectResponse())->setURI($profile_uri);
         }
     }
     $title = pht('Edit Profile Picture');
     $crumbs = $this->buildApplicationCrumbs();
     $crumbs->addTextCrumb($user->getUsername(), $profile_uri);
     $crumbs->addTextCrumb($title);
     $form = id(new PHUIFormLayoutView())->setUser($viewer);
     $default_image = PhabricatorFile::loadBuiltin($viewer, 'profile.png');
     $images = array();
     $current = $user->getProfileImagePHID();
     $has_current = false;
     if ($current) {
         $files = id(new PhabricatorFileQuery())->setViewer($viewer)->withPHIDs(array($current))->execute();
         if ($files) {
             $file = head($files);
             if ($file->isTransformableImage()) {
                 $has_current = true;
                 $images[$current] = array('uri' => $file->getBestURI(), 'tip' => pht('Current Picture'));
             }
         }
     }
     // Try to add external account images for any associated external accounts.
     $accounts = id(new PhabricatorExternalAccountQuery())->setViewer($viewer)->withUserPHIDs(array($user->getPHID()))->needImages(true)->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->execute();
     foreach ($accounts as $account) {
         $file = $account->getProfileImageFile();
         if ($account->getProfileImagePHID() != $file->getPHID()) {
             // This is a default image, just skip it.
             continue;
         }
         $provider = PhabricatorAuthProvider::getEnabledProviderByKey($account->getProviderKey());
         if ($provider) {
             $tip = pht('Picture From %s', $provider->getProviderName());
         } else {
             $tip = pht('Picture From External Account');
         }
         if ($file->isTransformableImage()) {
             $images[$file->getPHID()] = array('uri' => $file->getBestURI(), 'tip' => $tip);
         }
     }
     // Try to add Gravatar images for any email addresses associated with the
     // account.
     if (PhabricatorEnv::getEnvConfig('security.allow-outbound-http')) {
         $emails = id(new PhabricatorUserEmail())->loadAllWhere('userPHID = %s ORDER BY address', $user->getPHID());
         $futures = array();
         foreach ($emails as $email_object) {
             $email = $email_object->getAddress();
             $hash = md5(strtolower(trim($email)));
             $uri = id(new PhutilURI("https://secure.gravatar.com/avatar/{$hash}"))->setQueryParams(array('size' => 200, 'default' => '404', 'rating' => 'x'));
             $futures[$email] = new HTTPSFuture($uri);
         }
         $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
         foreach (Futures($futures) as $email => $future) {
             try {
                 list($body) = $future->resolvex();
                 $file = PhabricatorFile::newFromFileData($body, array('name' => 'profile-gravatar', 'ttl' => 60 * 60 * 4));
                 if ($file->isTransformableImage()) {
                     $images[$file->getPHID()] = array('uri' => $file->getBestURI(), 'tip' => pht('Gravatar for %s', $email));
                 }
             } catch (Exception $ex) {
                 // Just continue.
             }
         }
         unset($unguarded);
     }
     $images[PhabricatorPHIDConstants::PHID_VOID] = array('uri' => $default_image->getBestURI(), 'tip' => pht('Default Picture'));
     require_celerity_resource('people-profile-css');
     Javelin::initBehavior('phabricator-tooltips', array());
     $buttons = array();
     foreach ($images as $phid => $spec) {
         $button = javelin_tag('button', array('class' => 'grey profile-image-button', 'sigil' => 'has-tooltip', 'meta' => array('tip' => $spec['tip'], 'size' => 300)), phutil_tag('img', array('height' => 50, 'width' => 50, 'src' => $spec['uri'])));
         $button = array(phutil_tag('input', array('type' => 'hidden', 'name' => 'phid', 'value' => $phid)), $button);
         $button = phabricator_form($viewer, array('class' => 'profile-image-form', 'method' => 'POST'), $button);
         $buttons[] = $button;
     }
     if ($has_current) {
         $form->appendChild(id(new AphrontFormMarkupControl())->setLabel(pht('Current Picture'))->setValue(array_shift($buttons)));
     }
     $form->appendChild(id(new AphrontFormMarkupControl())->setLabel(pht('Use Picture'))->setValue($buttons));
     $form_box = id(new PHUIObjectBoxView())->setHeaderText($title)->setFormErrors($errors)->setForm($form);
     $upload_form = id(new AphrontFormView())->setUser($viewer)->setEncType('multipart/form-data')->appendChild(id(new AphrontFormFileControl())->setName('picture')->setLabel(pht('Upload Picture'))->setError($e_file)->setCaption(pht('Supported formats: %s', implode(', ', $supported_formats))))->appendChild(id(new AphrontFormSubmitControl())->addCancelButton($profile_uri)->setValue(pht('Upload Picture')));
     $upload_box = id(new PHUIObjectBoxView())->setHeaderText(pht('Upload New Picture'))->setForm($upload_form);
     return $this->buildApplicationPage(array($crumbs, $form_box, $upload_box), array('title' => $title));
 }