3 final class PhabricatorAuthUnlinkController
4 extends PhabricatorAuthController
{
6 public function handleRequest(AphrontRequest
$request) {
7 $viewer = $this->getViewer();
8 $id = $request->getURIData('id');
10 $account = id(new PhabricatorExternalAccountQuery())
13 ->requireCapabilities(
15 PhabricatorPolicyCapability
::CAN_VIEW
,
16 PhabricatorPolicyCapability
::CAN_EDIT
,
20 return new Aphront404Response();
23 $done_uri = '/settings/panel/external/';
25 $config = $account->getProviderConfig();
26 $provider = $config->getProvider();
27 if (!$provider->shouldAllowAccountUnlink()) {
28 return $this->renderNotUnlinkableErrorDialog($provider, $done_uri);
31 $confirmations = $request->getStrList('confirmations');
32 $confirmations = array_fuse($confirmations);
34 if (!$request->isFormOrHisecPost() ||
!isset($confirmations['unlink'])) {
35 return $this->renderConfirmDialog($confirmations, $config, $done_uri);
38 // Check that this account isn't the only account which can be used to
39 // login. We warn you when you remove your only login account.
40 if ($account->isUsableForLogin()) {
41 $other_accounts = id(new PhabricatorExternalAccountQuery())
43 ->withUserPHIDs(array($viewer->getPHID()))
47 foreach ($other_accounts as $other_account) {
48 if ($other_account->isUsableForLogin()) {
53 if ($valid_accounts < 2) {
54 if (!isset($confirmations['only'])) {
55 return $this->renderOnlyUsableAccountConfirmDialog(
62 $workflow_key = sprintf(
66 $hisec_token = id(new PhabricatorAuthSessionEngine())
67 ->setWorkflowKey($workflow_key)
68 ->requireHighSecurityToken($viewer, $request, $done_uri);
70 $account->unlinkAccount();
72 id(new PhabricatorAuthSessionEngine())->terminateLoginSessions(
74 new PhutilOpaqueEnvelope(
75 $request->getCookie(PhabricatorCookies
::COOKIE_SESSION
)));
77 return id(new AphrontRedirectResponse())->setURI($done_uri);
80 private function renderNotUnlinkableErrorDialog(
81 PhabricatorAuthProvider
$provider,
84 return $this->newDialog()
85 ->setTitle(pht('Permanent Account Link'))
88 'You can not unlink this account because the administrator has '.
89 'configured this server to make links to "%s" accounts permanent.',
90 $provider->getProviderName()))
91 ->addCancelButton($done_uri);
94 private function renderOnlyUsableAccountConfirmDialog(
98 $confirmations[] = 'only';
100 return $this->newDialog()
101 ->setTitle(pht('Unlink Your Only Login Account?'))
102 ->addHiddenInput('confirmations', implode(',', $confirmations))
105 'This is the only external login account linked to your Phabicator '.
106 'account. If you remove it, you may no longer be able to log in.'))
109 'If you lose access to your account, you can recover access by '.
110 'sending yourself an email login link from the login screen.'))
111 ->addCancelButton($done_uri)
112 ->addSubmitButton(pht('Unlink External Account'));
115 private function renderConfirmDialog(
116 array $confirmations,
117 PhabricatorAuthProviderConfig
$config,
120 $confirmations[] = 'unlink';
121 $provider = $config->getProvider();
123 $title = pht('Unlink "%s" Account?', $provider->getProviderName());
125 'You will no longer be able to use your %s account to '.
127 $provider->getProviderName());
129 return $this->newDialog()
131 ->addHiddenInput('confirmations', implode(',', $confirmations))
132 ->appendParagraph($body)
135 'Note: Unlinking an authentication provider will terminate any '.
136 'other active login sessions.'))
137 ->addSubmitButton(pht('Unlink Account'))
138 ->addCancelButton($done_uri);