@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
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Allow users to terminate login sessions

Summary:
This is partly a good feature, and partly should reduce false positives on HackerOne reporting things vaguely related to this.

Allow a user to terminate login sessions from the settings panel.

Test Plan:
- Terminated a session.
- Terminated all sessions.
- Tried to terminate all sessions again.
- Logged in with two browsers, terminated the other browser's session, reloaded, got kicked out.

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Differential Revision: https://secure.phabricator.com/D8556

+131 -3
+2
src/__phutil_library_map__.php
··· 1226 1226 'PhabricatorAuthSessionGarbageCollector' => 'applications/auth/garbagecollector/PhabricatorAuthSessionGarbageCollector.php', 1227 1227 'PhabricatorAuthSessionQuery' => 'applications/auth/query/PhabricatorAuthSessionQuery.php', 1228 1228 'PhabricatorAuthStartController' => 'applications/auth/controller/PhabricatorAuthStartController.php', 1229 + 'PhabricatorAuthTerminateSessionController' => 'applications/auth/controller/PhabricatorAuthTerminateSessionController.php', 1229 1230 'PhabricatorAuthUnlinkController' => 'applications/auth/controller/PhabricatorAuthUnlinkController.php', 1230 1231 'PhabricatorAuthValidateController' => 'applications/auth/controller/PhabricatorAuthValidateController.php', 1231 1232 'PhabricatorAuthenticationConfigOptions' => 'applications/config/option/PhabricatorAuthenticationConfigOptions.php', ··· 3910 3911 'PhabricatorAuthSessionGarbageCollector' => 'PhabricatorGarbageCollector', 3911 3912 'PhabricatorAuthSessionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 3912 3913 'PhabricatorAuthStartController' => 'PhabricatorAuthController', 3914 + 'PhabricatorAuthTerminateSessionController' => 'PhabricatorAuthController', 3913 3915 'PhabricatorAuthUnlinkController' => 'PhabricatorAuthController', 3914 3916 'PhabricatorAuthValidateController' => 'PhabricatorAuthController', 3915 3917 'PhabricatorAuthenticationConfigOptions' => 'PhabricatorApplicationConfigOptions',
+2
src/applications/auth/application/PhabricatorApplicationAuth.php
··· 86 86 => 'PhabricatorAuthLinkController', 87 87 'confirmlink/(?P<akey>[^/]+)/' 88 88 => 'PhabricatorAuthConfirmLinkController', 89 + 'session/terminate/(?P<id>[^/]+)/' 90 + => 'PhabricatorAuthTerminateSessionController', 89 91 ), 90 92 91 93 '/oauth/(?P<provider>\w+)/login/'
+83
src/applications/auth/controller/PhabricatorAuthTerminateSessionController.php
··· 1 + <?php 2 + 3 + final class PhabricatorAuthTerminateSessionController 4 + extends PhabricatorAuthController { 5 + 6 + private $id; 7 + 8 + public function willProcessRequest(array $data) { 9 + $this->id = $data['id']; 10 + } 11 + 12 + public function processRequest() { 13 + $request = $this->getRequest(); 14 + $viewer = $request->getUser(); 15 + 16 + $is_all = ($this->id === 'all'); 17 + 18 + $query = id(new PhabricatorAuthSessionQuery()) 19 + ->setViewer($viewer) 20 + ->withIdentityPHIDs(array($viewer->getPHID())); 21 + if (!$is_all) { 22 + $query->withIDs(array($this->id)); 23 + } 24 + 25 + $current_key = PhabricatorHash::digest( 26 + $request->getCookie(PhabricatorCookies::COOKIE_SESSION)); 27 + 28 + $sessions = $query->execute(); 29 + foreach ($sessions as $key => $session) { 30 + if ($session->getSessionKey() == $current_key) { 31 + // Don't terminate the current login session. 32 + unset($sessions[$key]); 33 + } 34 + } 35 + 36 + $panel_uri = '/settings/panel/sessions/'; 37 + 38 + if (!$sessions) { 39 + $dialog = id(new AphrontDialogView()) 40 + ->setUser($viewer) 41 + ->setTitle(pht('No Matching Sessions')) 42 + ->appendParagraph( 43 + pht('There are no matching sessions to terminate.')) 44 + ->appendParagraph( 45 + pht( 46 + '(You can not terminate your current login session. To '. 47 + 'terminate it, log out.)')) 48 + ->addCancelButton($panel_uri); 49 + 50 + return id(new AphrontDialogResponse())->setDialog($dialog); 51 + } 52 + 53 + if ($request->isDialogFormPost()) { 54 + foreach ($sessions as $session) { 55 + $session->delete(); 56 + } 57 + return id(new AphrontRedirectResponse())->setURI($panel_uri); 58 + } 59 + 60 + if ($is_all) { 61 + $title = pht('Terminate Sessions?'); 62 + $body = pht( 63 + 'Really terminate all sessions? (Your current login session will '. 64 + 'not be terminated.)'); 65 + } else { 66 + $title = pht('Terminate Session?'); 67 + $body = pht( 68 + 'Really terminate session %s?', 69 + phutil_tag('strong', array(), substr($session->getSessionKey(), 0, 6))); 70 + } 71 + 72 + $dialog = id(new AphrontDialogView()) 73 + ->setUser($viewer) 74 + ->setTitle($title) 75 + ->appendParagraph($body) 76 + ->addSubmitButton(pht('Terminate')) 77 + ->addCancelButton($panel_uri); 78 + 79 + return id(new AphrontDialogResponse())->setDialog($dialog); 80 + } 81 + 82 + 83 + }
+13
src/applications/auth/query/PhabricatorAuthSessionQuery.php
··· 3 3 final class PhabricatorAuthSessionQuery 4 4 extends PhabricatorCursorPagedPolicyAwareQuery { 5 5 6 + private $ids; 6 7 private $identityPHIDs; 7 8 private $sessionKeys; 8 9 private $sessionTypes; ··· 19 20 20 21 public function withSessionTypes(array $types) { 21 22 $this->sessionTypes = $types; 23 + return $this; 24 + } 25 + 26 + public function withIDs(array $ids) { 27 + $this->ids = $ids; 22 28 return $this; 23 29 } 24 30 ··· 61 67 62 68 protected function buildWhereClause(AphrontDatabaseConnection $conn_r) { 63 69 $where = array(); 70 + 71 + if ($this->ids) { 72 + $where[] = qsprintf( 73 + $conn_r, 74 + 'id IN (%Ld)', 75 + $this->ids); 76 + } 64 77 65 78 if ($this->identityPHIDs) { 66 79 $where[] = qsprintf(
+31 -3
src/applications/settings/panel/PhabricatorSettingsPanelSessions.php
··· 48 48 foreach ($sessions as $session) { 49 49 if ($session->getSessionKey() == $current_key) { 50 50 $rowc[] = 'highlighted'; 51 + $button = phutil_tag( 52 + 'a', 53 + array( 54 + 'class' => 'small grey button disabled', 55 + ), 56 + pht('Current')); 51 57 } else { 52 58 $rowc[] = null; 59 + $button = javelin_tag( 60 + 'a', 61 + array( 62 + 'href' => '/auth/session/terminate/'.$session->getID().'/', 63 + 'class' => 'small grey button', 64 + 'sigil' => 'workflow', 65 + ), 66 + pht('Terminate')); 53 67 } 54 68 55 69 $rows[] = array( 56 70 $handles[$session->getUserPHID()]->renderLink(), 57 - substr($session->getSessionKey(), 0, 12), 71 + substr($session->getSessionKey(), 0, 6), 58 72 $session->getType(), 59 73 phabricator_datetime($session->getSessionStart(), $viewer), 60 - phabricator_datetime($session->getSessionExpires(), $viewer), 74 + phabricator_date($session->getSessionExpires(), $viewer), 75 + $button, 61 76 ); 62 77 } 63 78 ··· 71 86 pht('Type'), 72 87 pht('Created'), 73 88 pht('Expires'), 89 + pht(''), 74 90 )); 75 91 $table->setColumnClasses( 76 92 array( ··· 79 95 '', 80 96 'right', 81 97 'right', 98 + 'action', 82 99 )); 83 100 84 101 102 + $terminate_icon = id(new PHUIIconView()) 103 + ->setSpriteSheet(PHUIIconView::SPRITE_ICONS) 104 + ->setSpriteIcon('warning'); 105 + $terminate_button = id(new PHUIButtonView()) 106 + ->setText(pht('Terminate All Sessions')) 107 + ->setHref('/auth/session/terminate/all/') 108 + ->setTag('a') 109 + ->setWorkflow(true) 110 + ->setIcon($terminate_icon); 111 + 85 112 $header = id(new PHUIHeaderView()) 86 - ->setHeader(pht('Active Login Sessions')); 113 + ->setHeader(pht('Active Login Sessions')) 114 + ->addActionLink($terminate_button); 87 115 88 116 $panel = id(new PHUIObjectBoxView()) 89 117 ->setHeader($header)