@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<?php
2
3final class PhabricatorHighSecurityRequestExceptionHandler
4 extends PhabricatorRequestExceptionHandler {
5
6 public function getRequestExceptionHandlerPriority() {
7 return 310000;
8 }
9
10 public function getRequestExceptionHandlerDescription() {
11 return pht(
12 'Handles high security exceptions which occur when a user needs '.
13 'to present MFA credentials to take an action.');
14 }
15
16 public function canHandleRequestThrowable(
17 AphrontRequest $request,
18 $throwable) {
19
20 if (!$this->isPhabricatorSite($request)) {
21 return false;
22 }
23
24 return ($throwable instanceof PhabricatorAuthHighSecurityRequiredException);
25 }
26
27 public function handleRequestThrowable(
28 AphrontRequest $request,
29 $throwable) {
30
31 $viewer = $this->getViewer($request);
32 $results = $throwable->getFactorValidationResults();
33
34 $form = id(new PhabricatorAuthSessionEngine())->renderHighSecurityForm(
35 $throwable->getFactors(),
36 $results,
37 $viewer,
38 $request);
39
40 $is_wait = false;
41 $is_continue = false;
42 foreach ($results as $result) {
43 if ($result->getIsWait()) {
44 $is_wait = true;
45 }
46
47 if ($result->getIsContinue()) {
48 $is_continue = true;
49 }
50 }
51
52 $is_upgrade = $throwable->getIsSessionUpgrade();
53
54 if ($is_upgrade) {
55 $title = pht('Enter High Security');
56 } else {
57 $title = pht('Provide MFA Credentials');
58 }
59
60 if ($is_wait) {
61 $submit = pht('Wait Patiently');
62 } else if ($is_upgrade && !$is_continue) {
63 $submit = pht('Enter High Security');
64 } else {
65 $submit = pht('Continue');
66 }
67
68 $dialog = id(new AphrontDialogView())
69 ->setUser($viewer)
70 ->setTitle($title)
71 ->setShortTitle(pht('Security Checkpoint'))
72 ->setWidth(AphrontDialogView::WIDTH_FORM)
73 ->addHiddenInput(AphrontRequest::TYPE_HISEC, true)
74 ->setSubmitURI($request->getPath())
75 ->addCancelButton($throwable->getCancelURI())
76 ->addSubmitButton($submit);
77
78 $form_layout = $form->buildLayoutView();
79
80 if ($is_upgrade) {
81 $message = pht(
82 'You are taking an action which requires you to enter '.
83 'high security.');
84
85 $info_view = id(new PHUIInfoView())
86 ->setSeverity(PHUIInfoView::SEVERITY_MFA)
87 ->setErrors(array($message));
88
89 $dialog
90 ->appendChild($info_view)
91 ->appendParagraph(
92 pht(
93 'To enter high security mode, confirm your credentials:'))
94 ->appendChild($form_layout)
95 ->appendParagraph(
96 pht(
97 'Your account will remain in high security mode for a short '.
98 'period of time. When you are finished taking sensitive '.
99 'actions, you should leave high security.'));
100 } else {
101 $message = pht(
102 'You are taking an action which requires you to provide '.
103 'multi-factor credentials.');
104
105 $info_view = id(new PHUIInfoView())
106 ->setSeverity(PHUIInfoView::SEVERITY_MFA)
107 ->setErrors(array($message));
108
109 $dialog
110 ->appendChild($info_view)
111 ->setErrors(
112 array(
113 ))
114 ->appendChild($form_layout);
115 }
116
117 $request_parameters = $request->getPassthroughRequestParameters(
118 $respect_quicksand = true);
119 foreach ($request_parameters as $key => $value) {
120 $dialog->addHiddenInput($key, $value);
121 }
122
123 // See T13289. If the user hit a "some transactions have no effect" dialog
124 // and elected to continue, we want to pass that flag through the MFA
125 // dialog even though it is not normally a passthrough request parameter.
126 if ($request->isContinueRequest()) {
127 $dialog->addHiddenInput(AphrontRequest::TYPE_CONTINUE, 1);
128 }
129
130 return $dialog;
131 }
132
133}