@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
at upstream/main 141 lines 4.4 kB view raw
1<?php 2 3final class PhabricatorAuthUnlinkController 4 extends PhabricatorAuthController { 5 6 public function handleRequest(AphrontRequest $request) { 7 $viewer = $this->getViewer(); 8 $id = $request->getURIData('id'); 9 10 $account = id(new PhabricatorExternalAccountQuery()) 11 ->setViewer($viewer) 12 ->withIDs(array($id)) 13 ->requireCapabilities( 14 array( 15 PhabricatorPolicyCapability::CAN_VIEW, 16 PhabricatorPolicyCapability::CAN_EDIT, 17 )) 18 ->executeOne(); 19 if (!$account) { 20 return new Aphront404Response(); 21 } 22 23 $done_uri = '/settings/panel/external/'; 24 25 $config = $account->getProviderConfig(); 26 $provider = $config->getProvider(); 27 if (!$provider->shouldAllowAccountUnlink()) { 28 return $this->renderNotUnlinkableErrorDialog($provider, $done_uri); 29 } 30 31 $confirmations = $request->getStrList('confirmations'); 32 $confirmations = array_fuse($confirmations); 33 34 if (!$request->isFormOrHisecPost() || !isset($confirmations['unlink'])) { 35 return $this->renderConfirmDialog($confirmations, $config, $done_uri); 36 } 37 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()) 42 ->setViewer($viewer) 43 ->withUserPHIDs(array($viewer->getPHID())) 44 ->execute(); 45 46 $valid_accounts = 0; 47 foreach ($other_accounts as $other_account) { 48 if ($other_account->isUsableForLogin()) { 49 $valid_accounts++; 50 } 51 } 52 53 if ($valid_accounts < 2) { 54 if (!isset($confirmations['only'])) { 55 return $this->renderOnlyUsableAccountConfirmDialog( 56 $confirmations, 57 $done_uri); 58 } 59 } 60 } 61 62 $workflow_key = sprintf( 63 'account.unlink(%s)', 64 $account->getPHID()); 65 66 $hisec_token = id(new PhabricatorAuthSessionEngine()) 67 ->setWorkflowKey($workflow_key) 68 ->requireHighSecurityToken($viewer, $request, $done_uri); 69 70 $account->unlinkAccount(); 71 72 id(new PhabricatorAuthSessionEngine())->terminateLoginSessions( 73 $viewer, 74 new PhutilOpaqueEnvelope( 75 $request->getCookie(PhabricatorCookies::COOKIE_SESSION))); 76 77 return id(new AphrontRedirectResponse())->setURI($done_uri); 78 } 79 80 private function renderNotUnlinkableErrorDialog( 81 PhabricatorAuthProvider $provider, 82 $done_uri) { 83 84 return $this->newDialog() 85 ->setTitle(pht('Permanent Account Link')) 86 ->appendChild( 87 pht( 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); 92 } 93 94 private function renderOnlyUsableAccountConfirmDialog( 95 array $confirmations, 96 $done_uri) { 97 98 $confirmations[] = 'only'; 99 100 return $this->newDialog() 101 ->setTitle(pht('Unlink Your Only Login Account?')) 102 ->addHiddenInput('confirmations', implode(',', $confirmations)) 103 ->appendParagraph( 104 pht( 105 'This is the only external login account linked to your '. 106 'account. If you remove it, you may no longer be able to log in.')) 107 ->appendParagraph( 108 pht( 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')); 113 } 114 115 private function renderConfirmDialog( 116 array $confirmations, 117 PhabricatorAuthProviderConfig $config, 118 $done_uri) { 119 120 $confirmations[] = 'unlink'; 121 $provider = $config->getProvider(); 122 123 $title = pht('Unlink "%s" Account?', $provider->getProviderName()); 124 $body = pht( 125 'You will no longer be able to use your %s account to '. 126 'log in.', 127 $provider->getProviderName()); 128 129 return $this->newDialog() 130 ->setTitle($title) 131 ->addHiddenInput('confirmations', implode(',', $confirmations)) 132 ->appendParagraph($body) 133 ->appendParagraph( 134 pht( 135 'Note: Unlinking an authentication provider will terminate any '. 136 'other active login sessions.')) 137 ->addSubmitButton(pht('Unlink Account')) 138 ->addCancelButton($done_uri); 139 } 140 141}