diff --git a/src/applications/auth/engine/PhabricatorAuthSessionEngine.php b/src/applications/auth/engine/PhabricatorAuthSessionEngine.php --- a/src/applications/auth/engine/PhabricatorAuthSessionEngine.php +++ b/src/applications/auth/engine/PhabricatorAuthSessionEngine.php @@ -213,26 +213,7 @@ $session = id(new PhabricatorAuthSession())->loadFromArray($session_dict); - $ttl = PhabricatorAuthSession::getSessionTypeTTL($session_type); - - // If more than 20% of the time on this session has been used, refresh the - // TTL back up to the full duration. The idea here is that sessions are - // good forever if used regularly, but get GC'd when they fall out of use. - - // NOTE: If we begin rotating session keys when extending sessions, the - // CSRF code needs to be updated so CSRF tokens survive session rotation. - - if (time() + (0.80 * $ttl) > $session->getSessionExpires()) { - $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); - $conn_w = $session_table->establishConnection('w'); - queryfx( - $conn_w, - 'UPDATE %T SET sessionExpires = UNIX_TIMESTAMP() + %d WHERE id = %d', - $session->getTableName(), - $ttl, - $session->getID()); - unset($unguarded); - } + $this->extendSession($session); // TODO: Remove this, see T13225. if ($is_weak) { @@ -284,7 +265,9 @@ $conn_w = $session_table->establishConnection('w'); // This has a side effect of validating the session type. - $session_ttl = PhabricatorAuthSession::getSessionTypeTTL($session_type); + $session_ttl = PhabricatorAuthSession::getSessionTypeTTL( + $session_type, + $partial); $digest_key = PhabricatorAuthSession::newSessionDigest( new PhutilOpaqueEnvelope($session_key)); @@ -1086,4 +1069,40 @@ } } + private function extendSession(PhabricatorAuthSession $session) { + $is_partial = $session->getIsPartial(); + + // Don't extend partial sessions. You have a relatively short window to + // upgrade into a full session, and your session expires otherwise. + if ($is_partial) { + return; + } + + $session_type = $session->getType(); + + $ttl = PhabricatorAuthSession::getSessionTypeTTL( + $session_type, + $session->getIsPartial()); + + // If more than 20% of the time on this session has been used, refresh the + // TTL back up to the full duration. The idea here is that sessions are + // good forever if used regularly, but get GC'd when they fall out of use. + + $now = PhabricatorTime::getNow(); + if ($now + (0.80 * $ttl) <= $session->getSessionExpires()) { + return; + } + + $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); + queryfx( + $session->establishConnection('w'), + 'UPDATE %R SET sessionExpires = UNIX_TIMESTAMP() + %d + WHERE id = %d', + $session, + $ttl, + $session->getID()); + unset($unguarded); + } + + } diff --git a/src/applications/auth/storage/PhabricatorAuthSession.php b/src/applications/auth/storage/PhabricatorAuthSession.php --- a/src/applications/auth/storage/PhabricatorAuthSession.php +++ b/src/applications/auth/storage/PhabricatorAuthSession.php @@ -72,10 +72,14 @@ return $this->assertAttached($this->identityObject); } - public static function getSessionTypeTTL($session_type) { + public static function getSessionTypeTTL($session_type, $is_partial) { switch ($session_type) { case self::TYPE_WEB: - return phutil_units('30 days in seconds'); + if ($is_partial) { + return phutil_units('30 minutes in seconds'); + } else { + return phutil_units('30 days in seconds'); + } case self::TYPE_CONDUIT: return phutil_units('24 hours in seconds'); default: