@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.

Give Duo MFA a stronger hint if users continue without answering the challenge

Summary: See PHI912. Also, clean up some leftover copy/pastey code here.

Test Plan: {F6182333}

Reviewers: amckinley

Reviewed By: amckinley

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

+59 -46
+21 -8
src/applications/auth/factor/PhabricatorAuthFactor.php
··· 123 123 ->setUserPHID($viewer->getPHID()) 124 124 ->setSessionPHID($viewer->getSession()->getPHID()) 125 125 ->setFactorPHID($config->getPHID()) 126 + ->setIsNewChallenge(true) 126 127 ->setWorkflowKey($engine->getWorkflowKey()); 127 128 } 128 129 ··· 283 284 284 285 $error = $result->getErrorMessage(); 285 286 286 - $icon = id(new PHUIIconView()) 287 - ->setIcon('fa-clock-o', 'red'); 287 + $icon = $result->getIcon(); 288 + if (!$icon) { 289 + $icon = id(new PHUIIconView()) 290 + ->setIcon('fa-clock-o', 'red'); 291 + } 288 292 289 293 return id(new PHUIFormTimerControl()) 290 294 ->setIcon($icon) ··· 295 299 private function newAnsweredControl( 296 300 PhabricatorAuthFactorResult $result) { 297 301 298 - $icon = id(new PHUIIconView()) 299 - ->setIcon('fa-check-circle-o', 'green'); 302 + $icon = $result->getIcon(); 303 + if (!$icon) { 304 + $icon = id(new PHUIIconView()) 305 + ->setIcon('fa-check-circle-o', 'green'); 306 + } 300 307 301 308 return id(new PHUIFormTimerControl()) 302 309 ->setIcon($icon) ··· 309 316 310 317 $error = $result->getErrorMessage(); 311 318 312 - $icon = id(new PHUIIconView()) 313 - ->setIcon('fa-times', 'red'); 319 + $icon = $result->getIcon(); 320 + if (!$icon) { 321 + $icon = id(new PHUIIconView()) 322 + ->setIcon('fa-times', 'red'); 323 + } 314 324 315 325 return id(new PHUIFormTimerControl()) 316 326 ->setIcon($icon) ··· 323 333 324 334 $error = $result->getErrorMessage(); 325 335 326 - $icon = id(new PHUIIconView()) 327 - ->setIcon('fa-commenting', 'green'); 336 + $icon = $result->getIcon(); 337 + if (!$icon) { 338 + $icon = id(new PHUIIconView()) 339 + ->setIcon('fa-commenting', 'green'); 340 + } 328 341 329 342 return id(new PHUIFormTimerControl()) 330 343 ->setIcon($icon)
+10
src/applications/auth/factor/PhabricatorAuthFactorResult.php
··· 10 10 private $errorMessage; 11 11 private $value; 12 12 private $issuedChallenges = array(); 13 + private $icon; 13 14 14 15 public function setAnsweredChallenge(PhabricatorAuthChallenge $challenge) { 15 16 if (!$challenge->getIsAnsweredChallenge()) { ··· 90 91 91 92 public function getIssuedChallenges() { 92 93 return $this->issuedChallenges; 94 + } 95 + 96 + public function setIcon(PHUIIconView $icon) { 97 + $this->icon = $icon; 98 + return $this; 99 + } 100 + 101 + public function getIcon() { 102 + return $this->icon; 93 103 } 94 104 95 105 }
+18 -38
src/applications/auth/factor/PhabricatorDuoAuthFactor.php
··· 612 612 return $this->newResult() 613 613 ->setAnsweredChallenge($challenge); 614 614 case 'waiting': 615 - // No result yet, we'll render a default state later on. 615 + // If we didn't just issue this challenge, give the user a stronger 616 + // hint that they need to follow the instructions. 617 + if (!$challenge->getIsNewChallenge()) { 618 + return $this->newResult() 619 + ->setIsContinue(true) 620 + ->setIcon( 621 + id(new PHUIIconView()) 622 + ->setIcon('fa-exclamation-triangle', 'yellow')) 623 + ->setErrorMessage( 624 + pht( 625 + 'You must approve the challenge which was sent to your '. 626 + 'phone. Open the Duo application and confirm the challenge, '. 627 + 'then continue.')); 628 + } 629 + 630 + // Otherwise, we'll construct a default message later on. 616 631 break; 617 632 default: 618 633 case 'deny': ··· 666 681 public function getRequestHasChallengeResponse( 667 682 PhabricatorAuthFactorConfig $config, 668 683 AphrontRequest $request) { 669 - $value = $this->getChallengeResponseFromRequest($config, $request); 670 - return (bool)strlen($value); 684 + return false; 671 685 } 672 686 673 687 protected function newResultFromChallengeResponse( ··· 675 689 PhabricatorUser $viewer, 676 690 AphrontRequest $request, 677 691 array $challenges) { 678 - 679 - $challenge = $this->getChallengeForCurrentContext( 680 - $config, 681 - $viewer, 682 - $challenges); 683 - 684 - $code = $this->getChallengeResponseFromRequest( 685 - $config, 686 - $request); 687 - 688 - $result = $this->newResult() 689 - ->setValue($code); 690 - 691 - if ($challenge->getIsAnsweredChallenge()) { 692 - return $result->setAnsweredChallenge($challenge); 693 - } 694 - 695 - if (phutil_hashes_are_identical($code, $challenge->getChallengeKey())) { 696 - $ttl = PhabricatorTime::getNow() + phutil_units('15 minutes in seconds'); 697 - 698 - $challenge 699 - ->markChallengeAsAnswered($ttl); 700 - 701 - return $result->setAnsweredChallenge($challenge); 702 - } 703 - 704 - if (strlen($code)) { 705 - $error_message = pht('Invalid'); 706 - } else { 707 - $error_message = pht('Required'); 708 - } 709 - 710 - $result->setErrorMessage($error_message); 711 - 712 - return $result; 692 + return $this->newResult(); 713 693 } 714 694 715 695 private function newDuoFuture(PhabricatorAuthFactorProvider $provider) {
+10
src/applications/auth/storage/PhabricatorAuthChallenge.php
··· 16 16 protected $properties = array(); 17 17 18 18 private $responseToken; 19 + private $isNewChallenge; 19 20 20 21 const HTTPKEY = '__hisec.challenges__'; 21 22 const TOKEN_DIGEST_KEY = 'auth.challenge.token'; ··· 239 240 240 241 public function getProperty($key, $default = null) { 241 242 return $this->properties[$key]; 243 + } 244 + 245 + public function setIsNewChallenge($is_new_challenge) { 246 + $this->isNewChallenge = $is_new_challenge; 247 + return $this; 248 + } 249 + 250 + public function getIsNewChallenge() { 251 + return $this->isNewChallenge; 242 252 } 243 253 244 254