mirror of
https://we.phorge.it/source/phorge.git
synced 2025-01-17 02:01:13 +01:00
Modularize Aphront exception handling
Summary: Ref T1806. Ref T7173. Depends on D14047. Currently, all exception handling is in this big messy clump in `AphrontDefaultApplicationConfiguration`. Split it out into modular classes. This will let a future change add new classes in the Phacility cluster which intercept particular exceptions we care about and replaces the default, generic responses with more useful, tailored responses. Test Plan: {F777391} - Hit a Conduit error (made a method throw). - Hit an Ajax error (made comment preview throw). - Hit a high security error (tried to edit TOTP). - Hit a rate limiting error (added a bunch of email addresses). - Hit a policy error (tried to look at something with no permission). - Hit an arbitrary exception (made a randomc ontroller throw). Reviewers: chad Reviewed By: chad Maniphest Tasks: T1806, T7173 Differential Revision: https://secure.phabricator.com/D14049
This commit is contained in:
parent
20ce1a905f
commit
1fc60a9a6e
15 changed files with 550 additions and 218 deletions
|
@ -157,6 +157,7 @@ phutil_register_library_map(array(
|
||||||
'AphrontRedirectResponseTestCase' => 'aphront/response/__tests__/AphrontRedirectResponseTestCase.php',
|
'AphrontRedirectResponseTestCase' => 'aphront/response/__tests__/AphrontRedirectResponseTestCase.php',
|
||||||
'AphrontReloadResponse' => 'aphront/response/AphrontReloadResponse.php',
|
'AphrontReloadResponse' => 'aphront/response/AphrontReloadResponse.php',
|
||||||
'AphrontRequest' => 'aphront/AphrontRequest.php',
|
'AphrontRequest' => 'aphront/AphrontRequest.php',
|
||||||
|
'AphrontRequestExceptionHandler' => 'aphront/handler/AphrontRequestExceptionHandler.php',
|
||||||
'AphrontRequestTestCase' => 'aphront/__tests__/AphrontRequestTestCase.php',
|
'AphrontRequestTestCase' => 'aphront/__tests__/AphrontRequestTestCase.php',
|
||||||
'AphrontResponse' => 'aphront/response/AphrontResponse.php',
|
'AphrontResponse' => 'aphront/response/AphrontResponse.php',
|
||||||
'AphrontResponseProducerInterface' => 'aphront/interface/AphrontResponseProducerInterface.php',
|
'AphrontResponseProducerInterface' => 'aphront/interface/AphrontResponseProducerInterface.php',
|
||||||
|
@ -1484,6 +1485,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorActionView' => 'view/layout/PhabricatorActionView.php',
|
'PhabricatorActionView' => 'view/layout/PhabricatorActionView.php',
|
||||||
'PhabricatorActivitySettingsPanel' => 'applications/settings/panel/PhabricatorActivitySettingsPanel.php',
|
'PhabricatorActivitySettingsPanel' => 'applications/settings/panel/PhabricatorActivitySettingsPanel.php',
|
||||||
'PhabricatorAdministratorsPolicyRule' => 'applications/policy/rule/PhabricatorAdministratorsPolicyRule.php',
|
'PhabricatorAdministratorsPolicyRule' => 'applications/policy/rule/PhabricatorAdministratorsPolicyRule.php',
|
||||||
|
'PhabricatorAjaxRequestExceptionHandler' => 'aphront/handler/PhabricatorAjaxRequestExceptionHandler.php',
|
||||||
'PhabricatorAlmanacApplication' => 'applications/almanac/application/PhabricatorAlmanacApplication.php',
|
'PhabricatorAlmanacApplication' => 'applications/almanac/application/PhabricatorAlmanacApplication.php',
|
||||||
'PhabricatorAmazonAuthProvider' => 'applications/auth/provider/PhabricatorAmazonAuthProvider.php',
|
'PhabricatorAmazonAuthProvider' => 'applications/auth/provider/PhabricatorAmazonAuthProvider.php',
|
||||||
'PhabricatorAnchorView' => 'view/layout/PhabricatorAnchorView.php',
|
'PhabricatorAnchorView' => 'view/layout/PhabricatorAnchorView.php',
|
||||||
|
@ -1786,6 +1788,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorConduitLogQuery' => 'applications/conduit/query/PhabricatorConduitLogQuery.php',
|
'PhabricatorConduitLogQuery' => 'applications/conduit/query/PhabricatorConduitLogQuery.php',
|
||||||
'PhabricatorConduitMethodCallLog' => 'applications/conduit/storage/PhabricatorConduitMethodCallLog.php',
|
'PhabricatorConduitMethodCallLog' => 'applications/conduit/storage/PhabricatorConduitMethodCallLog.php',
|
||||||
'PhabricatorConduitMethodQuery' => 'applications/conduit/query/PhabricatorConduitMethodQuery.php',
|
'PhabricatorConduitMethodQuery' => 'applications/conduit/query/PhabricatorConduitMethodQuery.php',
|
||||||
|
'PhabricatorConduitRequestExceptionHandler' => 'aphront/handler/PhabricatorConduitRequestExceptionHandler.php',
|
||||||
'PhabricatorConduitSearchEngine' => 'applications/conduit/query/PhabricatorConduitSearchEngine.php',
|
'PhabricatorConduitSearchEngine' => 'applications/conduit/query/PhabricatorConduitSearchEngine.php',
|
||||||
'PhabricatorConduitTestCase' => '__tests__/PhabricatorConduitTestCase.php',
|
'PhabricatorConduitTestCase' => '__tests__/PhabricatorConduitTestCase.php',
|
||||||
'PhabricatorConduitToken' => 'applications/conduit/storage/PhabricatorConduitToken.php',
|
'PhabricatorConduitToken' => 'applications/conduit/storage/PhabricatorConduitToken.php',
|
||||||
|
@ -1838,6 +1841,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorConfigOptionType' => 'applications/config/custom/PhabricatorConfigOptionType.php',
|
'PhabricatorConfigOptionType' => 'applications/config/custom/PhabricatorConfigOptionType.php',
|
||||||
'PhabricatorConfigPHIDModule' => 'applications/config/module/PhabricatorConfigPHIDModule.php',
|
'PhabricatorConfigPHIDModule' => 'applications/config/module/PhabricatorConfigPHIDModule.php',
|
||||||
'PhabricatorConfigProxySource' => 'infrastructure/env/PhabricatorConfigProxySource.php',
|
'PhabricatorConfigProxySource' => 'infrastructure/env/PhabricatorConfigProxySource.php',
|
||||||
|
'PhabricatorConfigRequestExceptionHandlerModule' => 'applications/config/module/PhabricatorConfigRequestExceptionHandlerModule.php',
|
||||||
'PhabricatorConfigResponse' => 'applications/config/response/PhabricatorConfigResponse.php',
|
'PhabricatorConfigResponse' => 'applications/config/response/PhabricatorConfigResponse.php',
|
||||||
'PhabricatorConfigSchemaQuery' => 'applications/config/schema/PhabricatorConfigSchemaQuery.php',
|
'PhabricatorConfigSchemaQuery' => 'applications/config/schema/PhabricatorConfigSchemaQuery.php',
|
||||||
'PhabricatorConfigSchemaSpec' => 'applications/config/schema/PhabricatorConfigSchemaSpec.php',
|
'PhabricatorConfigSchemaSpec' => 'applications/config/schema/PhabricatorConfigSchemaSpec.php',
|
||||||
|
@ -1993,6 +1997,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorDatabaseSetupCheck' => 'applications/config/check/PhabricatorDatabaseSetupCheck.php',
|
'PhabricatorDatabaseSetupCheck' => 'applications/config/check/PhabricatorDatabaseSetupCheck.php',
|
||||||
'PhabricatorDateTimeSettingsPanel' => 'applications/settings/panel/PhabricatorDateTimeSettingsPanel.php',
|
'PhabricatorDateTimeSettingsPanel' => 'applications/settings/panel/PhabricatorDateTimeSettingsPanel.php',
|
||||||
'PhabricatorDebugController' => 'applications/system/controller/PhabricatorDebugController.php',
|
'PhabricatorDebugController' => 'applications/system/controller/PhabricatorDebugController.php',
|
||||||
|
'PhabricatorDefaultRequestExceptionHandler' => 'aphront/handler/PhabricatorDefaultRequestExceptionHandler.php',
|
||||||
'PhabricatorDesktopNotificationsSettingsPanel' => 'applications/settings/panel/PhabricatorDesktopNotificationsSettingsPanel.php',
|
'PhabricatorDesktopNotificationsSettingsPanel' => 'applications/settings/panel/PhabricatorDesktopNotificationsSettingsPanel.php',
|
||||||
'PhabricatorDestructibleInterface' => 'applications/system/interface/PhabricatorDestructibleInterface.php',
|
'PhabricatorDestructibleInterface' => 'applications/system/interface/PhabricatorDestructibleInterface.php',
|
||||||
'PhabricatorDestructionEngine' => 'applications/system/engine/PhabricatorDestructionEngine.php',
|
'PhabricatorDestructionEngine' => 'applications/system/engine/PhabricatorDestructionEngine.php',
|
||||||
|
@ -2183,6 +2188,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorHelpEditorProtocolController' => 'applications/help/controller/PhabricatorHelpEditorProtocolController.php',
|
'PhabricatorHelpEditorProtocolController' => 'applications/help/controller/PhabricatorHelpEditorProtocolController.php',
|
||||||
'PhabricatorHelpKeyboardShortcutController' => 'applications/help/controller/PhabricatorHelpKeyboardShortcutController.php',
|
'PhabricatorHelpKeyboardShortcutController' => 'applications/help/controller/PhabricatorHelpKeyboardShortcutController.php',
|
||||||
'PhabricatorHeraldApplication' => 'applications/herald/application/PhabricatorHeraldApplication.php',
|
'PhabricatorHeraldApplication' => 'applications/herald/application/PhabricatorHeraldApplication.php',
|
||||||
|
'PhabricatorHighSecurityRequestExceptionHandler' => 'aphront/handler/PhabricatorHighSecurityRequestExceptionHandler.php',
|
||||||
'PhabricatorHomeApplication' => 'applications/home/application/PhabricatorHomeApplication.php',
|
'PhabricatorHomeApplication' => 'applications/home/application/PhabricatorHomeApplication.php',
|
||||||
'PhabricatorHomeController' => 'applications/home/controller/PhabricatorHomeController.php',
|
'PhabricatorHomeController' => 'applications/home/controller/PhabricatorHomeController.php',
|
||||||
'PhabricatorHomeMainController' => 'applications/home/controller/PhabricatorHomeMainController.php',
|
'PhabricatorHomeMainController' => 'applications/home/controller/PhabricatorHomeMainController.php',
|
||||||
|
@ -2580,6 +2586,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorPolicyManagementWorkflow' => 'applications/policy/management/PhabricatorPolicyManagementWorkflow.php',
|
'PhabricatorPolicyManagementWorkflow' => 'applications/policy/management/PhabricatorPolicyManagementWorkflow.php',
|
||||||
'PhabricatorPolicyPHIDTypePolicy' => 'applications/policy/phid/PhabricatorPolicyPHIDTypePolicy.php',
|
'PhabricatorPolicyPHIDTypePolicy' => 'applications/policy/phid/PhabricatorPolicyPHIDTypePolicy.php',
|
||||||
'PhabricatorPolicyQuery' => 'applications/policy/query/PhabricatorPolicyQuery.php',
|
'PhabricatorPolicyQuery' => 'applications/policy/query/PhabricatorPolicyQuery.php',
|
||||||
|
'PhabricatorPolicyRequestExceptionHandler' => 'aphront/handler/PhabricatorPolicyRequestExceptionHandler.php',
|
||||||
'PhabricatorPolicyRule' => 'applications/policy/rule/PhabricatorPolicyRule.php',
|
'PhabricatorPolicyRule' => 'applications/policy/rule/PhabricatorPolicyRule.php',
|
||||||
'PhabricatorPolicyTestCase' => 'applications/policy/__tests__/PhabricatorPolicyTestCase.php',
|
'PhabricatorPolicyTestCase' => 'applications/policy/__tests__/PhabricatorPolicyTestCase.php',
|
||||||
'PhabricatorPolicyTestObject' => 'applications/policy/__tests__/PhabricatorPolicyTestObject.php',
|
'PhabricatorPolicyTestObject' => 'applications/policy/__tests__/PhabricatorPolicyTestObject.php',
|
||||||
|
@ -2667,6 +2674,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorQueryOrderItem' => 'infrastructure/query/order/PhabricatorQueryOrderItem.php',
|
'PhabricatorQueryOrderItem' => 'infrastructure/query/order/PhabricatorQueryOrderItem.php',
|
||||||
'PhabricatorQueryOrderTestCase' => 'infrastructure/query/order/__tests__/PhabricatorQueryOrderTestCase.php',
|
'PhabricatorQueryOrderTestCase' => 'infrastructure/query/order/__tests__/PhabricatorQueryOrderTestCase.php',
|
||||||
'PhabricatorQueryOrderVector' => 'infrastructure/query/order/PhabricatorQueryOrderVector.php',
|
'PhabricatorQueryOrderVector' => 'infrastructure/query/order/PhabricatorQueryOrderVector.php',
|
||||||
|
'PhabricatorRateLimitRequestExceptionHandler' => 'aphront/handler/PhabricatorRateLimitRequestExceptionHandler.php',
|
||||||
'PhabricatorRecaptchaConfigOptions' => 'applications/config/option/PhabricatorRecaptchaConfigOptions.php',
|
'PhabricatorRecaptchaConfigOptions' => 'applications/config/option/PhabricatorRecaptchaConfigOptions.php',
|
||||||
'PhabricatorRecipientHasBadgeEdgeType' => 'applications/badges/edge/PhabricatorRecipientHasBadgeEdgeType.php',
|
'PhabricatorRecipientHasBadgeEdgeType' => 'applications/badges/edge/PhabricatorRecipientHasBadgeEdgeType.php',
|
||||||
'PhabricatorRedirectController' => 'applications/base/controller/PhabricatorRedirectController.php',
|
'PhabricatorRedirectController' => 'applications/base/controller/PhabricatorRedirectController.php',
|
||||||
|
@ -2758,6 +2766,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorRepositoryURITestCase' => 'applications/repository/storage/__tests__/PhabricatorRepositoryURITestCase.php',
|
'PhabricatorRepositoryURITestCase' => 'applications/repository/storage/__tests__/PhabricatorRepositoryURITestCase.php',
|
||||||
'PhabricatorRepositoryVCSPassword' => 'applications/repository/storage/PhabricatorRepositoryVCSPassword.php',
|
'PhabricatorRepositoryVCSPassword' => 'applications/repository/storage/PhabricatorRepositoryVCSPassword.php',
|
||||||
'PhabricatorRepositoryVersion' => 'applications/repository/constants/PhabricatorRepositoryVersion.php',
|
'PhabricatorRepositoryVersion' => 'applications/repository/constants/PhabricatorRepositoryVersion.php',
|
||||||
|
'PhabricatorRequestExceptionHandler' => 'aphront/handler/PhabricatorRequestExceptionHandler.php',
|
||||||
'PhabricatorResourceSite' => 'aphront/site/PhabricatorResourceSite.php',
|
'PhabricatorResourceSite' => 'aphront/site/PhabricatorResourceSite.php',
|
||||||
'PhabricatorRobotsController' => 'applications/system/controller/PhabricatorRobotsController.php',
|
'PhabricatorRobotsController' => 'applications/system/controller/PhabricatorRobotsController.php',
|
||||||
'PhabricatorS3FileStorageEngine' => 'applications/files/engine/PhabricatorS3FileStorageEngine.php',
|
'PhabricatorS3FileStorageEngine' => 'applications/files/engine/PhabricatorS3FileStorageEngine.php',
|
||||||
|
@ -3788,6 +3797,7 @@ phutil_register_library_map(array(
|
||||||
'AphrontRedirectResponseTestCase' => 'PhabricatorTestCase',
|
'AphrontRedirectResponseTestCase' => 'PhabricatorTestCase',
|
||||||
'AphrontReloadResponse' => 'AphrontRedirectResponse',
|
'AphrontReloadResponse' => 'AphrontRedirectResponse',
|
||||||
'AphrontRequest' => 'Phobject',
|
'AphrontRequest' => 'Phobject',
|
||||||
|
'AphrontRequestExceptionHandler' => 'Phobject',
|
||||||
'AphrontRequestTestCase' => 'PhabricatorTestCase',
|
'AphrontRequestTestCase' => 'PhabricatorTestCase',
|
||||||
'AphrontResponse' => 'Phobject',
|
'AphrontResponse' => 'Phobject',
|
||||||
'AphrontRoutingMap' => 'Phobject',
|
'AphrontRoutingMap' => 'Phobject',
|
||||||
|
@ -5303,6 +5313,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorActionView' => 'AphrontView',
|
'PhabricatorActionView' => 'AphrontView',
|
||||||
'PhabricatorActivitySettingsPanel' => 'PhabricatorSettingsPanel',
|
'PhabricatorActivitySettingsPanel' => 'PhabricatorSettingsPanel',
|
||||||
'PhabricatorAdministratorsPolicyRule' => 'PhabricatorPolicyRule',
|
'PhabricatorAdministratorsPolicyRule' => 'PhabricatorPolicyRule',
|
||||||
|
'PhabricatorAjaxRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler',
|
||||||
'PhabricatorAlmanacApplication' => 'PhabricatorApplication',
|
'PhabricatorAlmanacApplication' => 'PhabricatorApplication',
|
||||||
'PhabricatorAmazonAuthProvider' => 'PhabricatorOAuth2AuthProvider',
|
'PhabricatorAmazonAuthProvider' => 'PhabricatorOAuth2AuthProvider',
|
||||||
'PhabricatorAnchorView' => 'AphrontView',
|
'PhabricatorAnchorView' => 'AphrontView',
|
||||||
|
@ -5667,6 +5678,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorPolicyInterface',
|
'PhabricatorPolicyInterface',
|
||||||
),
|
),
|
||||||
'PhabricatorConduitMethodQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'PhabricatorConduitMethodQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
|
'PhabricatorConduitRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler',
|
||||||
'PhabricatorConduitSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
'PhabricatorConduitSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||||
'PhabricatorConduitTestCase' => 'PhabricatorTestCase',
|
'PhabricatorConduitTestCase' => 'PhabricatorTestCase',
|
||||||
'PhabricatorConduitToken' => array(
|
'PhabricatorConduitToken' => array(
|
||||||
|
@ -5729,6 +5741,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorConfigOptionType' => 'Phobject',
|
'PhabricatorConfigOptionType' => 'Phobject',
|
||||||
'PhabricatorConfigPHIDModule' => 'PhabricatorConfigModule',
|
'PhabricatorConfigPHIDModule' => 'PhabricatorConfigModule',
|
||||||
'PhabricatorConfigProxySource' => 'PhabricatorConfigSource',
|
'PhabricatorConfigProxySource' => 'PhabricatorConfigSource',
|
||||||
|
'PhabricatorConfigRequestExceptionHandlerModule' => 'PhabricatorConfigModule',
|
||||||
'PhabricatorConfigResponse' => 'AphrontStandaloneHTMLResponse',
|
'PhabricatorConfigResponse' => 'AphrontStandaloneHTMLResponse',
|
||||||
'PhabricatorConfigSchemaQuery' => 'Phobject',
|
'PhabricatorConfigSchemaQuery' => 'Phobject',
|
||||||
'PhabricatorConfigSchemaSpec' => 'Phobject',
|
'PhabricatorConfigSchemaSpec' => 'Phobject',
|
||||||
|
@ -5913,6 +5926,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorDatabaseSetupCheck' => 'PhabricatorSetupCheck',
|
'PhabricatorDatabaseSetupCheck' => 'PhabricatorSetupCheck',
|
||||||
'PhabricatorDateTimeSettingsPanel' => 'PhabricatorSettingsPanel',
|
'PhabricatorDateTimeSettingsPanel' => 'PhabricatorSettingsPanel',
|
||||||
'PhabricatorDebugController' => 'PhabricatorController',
|
'PhabricatorDebugController' => 'PhabricatorController',
|
||||||
|
'PhabricatorDefaultRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler',
|
||||||
'PhabricatorDesktopNotificationsSettingsPanel' => 'PhabricatorSettingsPanel',
|
'PhabricatorDesktopNotificationsSettingsPanel' => 'PhabricatorSettingsPanel',
|
||||||
'PhabricatorDestructionEngine' => 'Phobject',
|
'PhabricatorDestructionEngine' => 'Phobject',
|
||||||
'PhabricatorDeveloperConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
'PhabricatorDeveloperConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||||
|
@ -6138,6 +6152,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorHelpEditorProtocolController' => 'PhabricatorHelpController',
|
'PhabricatorHelpEditorProtocolController' => 'PhabricatorHelpController',
|
||||||
'PhabricatorHelpKeyboardShortcutController' => 'PhabricatorHelpController',
|
'PhabricatorHelpKeyboardShortcutController' => 'PhabricatorHelpController',
|
||||||
'PhabricatorHeraldApplication' => 'PhabricatorApplication',
|
'PhabricatorHeraldApplication' => 'PhabricatorApplication',
|
||||||
|
'PhabricatorHighSecurityRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler',
|
||||||
'PhabricatorHomeApplication' => 'PhabricatorApplication',
|
'PhabricatorHomeApplication' => 'PhabricatorApplication',
|
||||||
'PhabricatorHomeController' => 'PhabricatorController',
|
'PhabricatorHomeController' => 'PhabricatorController',
|
||||||
'PhabricatorHomeMainController' => 'PhabricatorHomeController',
|
'PhabricatorHomeMainController' => 'PhabricatorHomeController',
|
||||||
|
@ -6587,6 +6602,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorPolicyManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
'PhabricatorPolicyManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
||||||
'PhabricatorPolicyPHIDTypePolicy' => 'PhabricatorPHIDType',
|
'PhabricatorPolicyPHIDTypePolicy' => 'PhabricatorPHIDType',
|
||||||
'PhabricatorPolicyQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'PhabricatorPolicyQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
|
'PhabricatorPolicyRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler',
|
||||||
'PhabricatorPolicyRule' => 'Phobject',
|
'PhabricatorPolicyRule' => 'Phobject',
|
||||||
'PhabricatorPolicyTestCase' => 'PhabricatorTestCase',
|
'PhabricatorPolicyTestCase' => 'PhabricatorTestCase',
|
||||||
'PhabricatorPolicyTestObject' => array(
|
'PhabricatorPolicyTestObject' => array(
|
||||||
|
@ -6702,6 +6718,7 @@ phutil_register_library_map(array(
|
||||||
'Phobject',
|
'Phobject',
|
||||||
'Iterator',
|
'Iterator',
|
||||||
),
|
),
|
||||||
|
'PhabricatorRateLimitRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler',
|
||||||
'PhabricatorRecaptchaConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
'PhabricatorRecaptchaConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||||
'PhabricatorRecipientHasBadgeEdgeType' => 'PhabricatorEdgeType',
|
'PhabricatorRecipientHasBadgeEdgeType' => 'PhabricatorEdgeType',
|
||||||
'PhabricatorRedirectController' => 'PhabricatorController',
|
'PhabricatorRedirectController' => 'PhabricatorController',
|
||||||
|
@ -6828,6 +6845,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorRepositoryURITestCase' => 'PhabricatorTestCase',
|
'PhabricatorRepositoryURITestCase' => 'PhabricatorTestCase',
|
||||||
'PhabricatorRepositoryVCSPassword' => 'PhabricatorRepositoryDAO',
|
'PhabricatorRepositoryVCSPassword' => 'PhabricatorRepositoryDAO',
|
||||||
'PhabricatorRepositoryVersion' => 'Phobject',
|
'PhabricatorRepositoryVersion' => 'Phobject',
|
||||||
|
'PhabricatorRequestExceptionHandler' => 'AphrontRequestExceptionHandler',
|
||||||
'PhabricatorResourceSite' => 'PhabricatorSite',
|
'PhabricatorResourceSite' => 'PhabricatorSite',
|
||||||
'PhabricatorRobotsController' => 'PhabricatorController',
|
'PhabricatorRobotsController' => 'PhabricatorController',
|
||||||
'PhabricatorS3FileStorageEngine' => 'PhabricatorFileStorageEngine',
|
'PhabricatorS3FileStorageEngine' => 'PhabricatorFileStorageEngine',
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
/**
|
/**
|
||||||
* @task routing URI Routing
|
* @task routing URI Routing
|
||||||
* @task response Response Handling
|
* @task response Response Handling
|
||||||
|
* @task exception Exception Handling
|
||||||
*/
|
*/
|
||||||
abstract class AphrontApplicationConfiguration extends Phobject {
|
abstract class AphrontApplicationConfiguration extends Phobject {
|
||||||
|
|
||||||
|
@ -11,7 +12,6 @@ abstract class AphrontApplicationConfiguration extends Phobject {
|
||||||
private $path;
|
private $path;
|
||||||
private $console;
|
private $console;
|
||||||
|
|
||||||
abstract public function getApplicationName();
|
|
||||||
abstract public function buildRequest();
|
abstract public function buildRequest();
|
||||||
abstract public function build404Controller();
|
abstract public function build404Controller();
|
||||||
abstract public function buildRedirectController($uri, $external);
|
abstract public function buildRedirectController($uri, $external);
|
||||||
|
@ -482,7 +482,7 @@ abstract class AphrontApplicationConfiguration extends Phobject {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verifies that the erturn value from an
|
* Verifies that the return value from an
|
||||||
* @{class:AphrontResponseProducerInterface} is of an allowed type.
|
* @{class:AphrontResponseProducerInterface} is of an allowed type.
|
||||||
*
|
*
|
||||||
* @param AphrontResponseProducerInterface Object which produced
|
* @param AphrontResponseProducerInterface Object which produced
|
||||||
|
@ -511,6 +511,36 @@ abstract class AphrontApplicationConfiguration extends Phobject {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies that the return value from an
|
||||||
|
* @{class:AphrontRequestExceptionHandler} is of an allowed type.
|
||||||
|
*
|
||||||
|
* @param AphrontRequestExceptionHandler Object which produced this
|
||||||
|
* response.
|
||||||
|
* @param wild Supposedly valid response.
|
||||||
|
* @return void
|
||||||
|
* @task response
|
||||||
|
*/
|
||||||
|
private function validateErrorHandlerResponse(
|
||||||
|
AphrontRequestExceptionHandler $handler,
|
||||||
|
$response) {
|
||||||
|
|
||||||
|
if ($this->isValidResponseObject($response)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Exception handler "%s" returned an invalid response from call to '.
|
||||||
|
'"%s". This method must return an object of class "%s", or an object '.
|
||||||
|
'which implements the "%s" interface.',
|
||||||
|
get_class($handler),
|
||||||
|
'handleRequestException()',
|
||||||
|
'AphrontResponse',
|
||||||
|
'AphrontResponseProducerInterface'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves a response object into an @{class:AphrontResponse}.
|
* Resolves a response object into an @{class:AphrontResponse}.
|
||||||
*
|
*
|
||||||
|
@ -572,4 +602,34 @@ abstract class AphrontApplicationConfiguration extends Phobject {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( Error Handling )----------------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert an exception which has escaped the controller into a response.
|
||||||
|
*
|
||||||
|
* This method delegates exception handling to available subclasses of
|
||||||
|
* @{class:AphrontRequestExceptionHandler}.
|
||||||
|
*
|
||||||
|
* @param Exception Exception which needs to be handled.
|
||||||
|
* @return wild Response or response producer, or null if no available
|
||||||
|
* handler can produce a response.
|
||||||
|
* @task exception
|
||||||
|
*/
|
||||||
|
private function handleException(Exception $ex) {
|
||||||
|
$handlers = AphrontRequestExceptionHandler::getAllHandlers();
|
||||||
|
|
||||||
|
$request = $this->getRequest();
|
||||||
|
foreach ($handlers as $handler) {
|
||||||
|
if ($handler->canHandleRequestException($request, $ex)) {
|
||||||
|
$response = $handler->handleRequestException($request, $ex);
|
||||||
|
$this->validateErrorHandlerResponse($handler, $response);
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw $ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,12 +8,6 @@
|
||||||
class AphrontDefaultApplicationConfiguration
|
class AphrontDefaultApplicationConfiguration
|
||||||
extends AphrontApplicationConfiguration {
|
extends AphrontApplicationConfiguration {
|
||||||
|
|
||||||
public function __construct() {}
|
|
||||||
|
|
||||||
public function getApplicationName() {
|
|
||||||
return 'aphront-default';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @phutil-external-symbol class PhabricatorStartup
|
* @phutil-external-symbol class PhabricatorStartup
|
||||||
*/
|
*/
|
||||||
|
@ -50,213 +44,6 @@ class AphrontDefaultApplicationConfiguration
|
||||||
return $request;
|
return $request;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleException(Exception $ex) {
|
|
||||||
$request = $this->getRequest();
|
|
||||||
|
|
||||||
// For Conduit requests, return a Conduit response.
|
|
||||||
if ($request->isConduit()) {
|
|
||||||
$response = new ConduitAPIResponse();
|
|
||||||
$response->setErrorCode(get_class($ex));
|
|
||||||
$response->setErrorInfo($ex->getMessage());
|
|
||||||
|
|
||||||
return id(new AphrontJSONResponse())
|
|
||||||
->setAddJSONShield(false)
|
|
||||||
->setContent($response->toDictionary());
|
|
||||||
}
|
|
||||||
|
|
||||||
// For non-workflow requests, return a Ajax response.
|
|
||||||
if ($request->isAjax() && !$request->isWorkflow()) {
|
|
||||||
// Log these; they don't get shown on the client and can be difficult
|
|
||||||
// to debug.
|
|
||||||
phlog($ex);
|
|
||||||
|
|
||||||
$response = new AphrontAjaxResponse();
|
|
||||||
$response->setError(
|
|
||||||
array(
|
|
||||||
'code' => get_class($ex),
|
|
||||||
'info' => $ex->getMessage(),
|
|
||||||
));
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
$user = $request->getUser();
|
|
||||||
if (!$user) {
|
|
||||||
// If we hit an exception very early, we won't have a user.
|
|
||||||
$user = new PhabricatorUser();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($ex instanceof PhabricatorSystemActionRateLimitException) {
|
|
||||||
$dialog = id(new AphrontDialogView())
|
|
||||||
->setTitle(pht('Slow Down!'))
|
|
||||||
->setUser($user)
|
|
||||||
->setErrors(array(pht('You are being rate limited.')))
|
|
||||||
->appendParagraph($ex->getMessage())
|
|
||||||
->appendParagraph($ex->getRateExplanation())
|
|
||||||
->addCancelButton('/', pht('Okaaaaaaaaaaaaaay...'));
|
|
||||||
|
|
||||||
$response = new AphrontDialogResponse();
|
|
||||||
$response->setDialog($dialog);
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($ex instanceof PhabricatorAuthHighSecurityRequiredException) {
|
|
||||||
|
|
||||||
$form = id(new PhabricatorAuthSessionEngine())->renderHighSecurityForm(
|
|
||||||
$ex->getFactors(),
|
|
||||||
$ex->getFactorValidationResults(),
|
|
||||||
$user,
|
|
||||||
$request);
|
|
||||||
|
|
||||||
$dialog = id(new AphrontDialogView())
|
|
||||||
->setUser($user)
|
|
||||||
->setTitle(pht('Entering High Security'))
|
|
||||||
->setShortTitle(pht('Security Checkpoint'))
|
|
||||||
->setWidth(AphrontDialogView::WIDTH_FORM)
|
|
||||||
->addHiddenInput(AphrontRequest::TYPE_HISEC, true)
|
|
||||||
->setErrors(
|
|
||||||
array(
|
|
||||||
pht(
|
|
||||||
'You are taking an action which requires you to enter '.
|
|
||||||
'high security.'),
|
|
||||||
))
|
|
||||||
->appendParagraph(
|
|
||||||
pht(
|
|
||||||
'High security mode helps protect your account from security '.
|
|
||||||
'threats, like session theft or someone messing with your stuff '.
|
|
||||||
'while you\'re grabbing a coffee. To enter high security mode, '.
|
|
||||||
'confirm your credentials.'))
|
|
||||||
->appendChild($form->buildLayoutView())
|
|
||||||
->appendParagraph(
|
|
||||||
pht(
|
|
||||||
'Your account will remain in high security mode for a short '.
|
|
||||||
'period of time. When you are finished taking sensitive '.
|
|
||||||
'actions, you should leave high security.'))
|
|
||||||
->setSubmitURI($request->getPath())
|
|
||||||
->addCancelButton($ex->getCancelURI())
|
|
||||||
->addSubmitButton(pht('Enter High Security'));
|
|
||||||
|
|
||||||
$request_parameters = $request->getPassthroughRequestParameters(
|
|
||||||
$respect_quicksand = true);
|
|
||||||
foreach ($request_parameters as $key => $value) {
|
|
||||||
$dialog->addHiddenInput($key, $value);
|
|
||||||
}
|
|
||||||
|
|
||||||
$response = new AphrontDialogResponse();
|
|
||||||
$response->setDialog($dialog);
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($ex instanceof PhabricatorPolicyException) {
|
|
||||||
if (!$user->isLoggedIn()) {
|
|
||||||
// If the user isn't logged in, just give them a login form. This is
|
|
||||||
// probably a generally more useful response than a policy dialog that
|
|
||||||
// they have to click through to get a login form.
|
|
||||||
//
|
|
||||||
// Possibly we should add a header here like "you need to login to see
|
|
||||||
// the thing you are trying to look at".
|
|
||||||
$login_controller = new PhabricatorAuthStartController();
|
|
||||||
$login_controller->setRequest($request);
|
|
||||||
|
|
||||||
$auth_app_class = 'PhabricatorAuthApplication';
|
|
||||||
$auth_app = PhabricatorApplication::getByClass($auth_app_class);
|
|
||||||
$login_controller->setCurrentApplication($auth_app);
|
|
||||||
|
|
||||||
return $login_controller->handleRequest($request);
|
|
||||||
}
|
|
||||||
|
|
||||||
$content = array(
|
|
||||||
phutil_tag(
|
|
||||||
'div',
|
|
||||||
array(
|
|
||||||
'class' => 'aphront-policy-rejection',
|
|
||||||
),
|
|
||||||
$ex->getRejection()),
|
|
||||||
);
|
|
||||||
|
|
||||||
$list = null;
|
|
||||||
if ($ex->getCapabilityName()) {
|
|
||||||
$list = $ex->getMoreInfo();
|
|
||||||
foreach ($list as $key => $item) {
|
|
||||||
$list[$key] = $item;
|
|
||||||
}
|
|
||||||
|
|
||||||
$content[] = phutil_tag(
|
|
||||||
'div',
|
|
||||||
array(
|
|
||||||
'class' => 'aphront-capability-details',
|
|
||||||
),
|
|
||||||
pht('Users with the "%s" capability:', $ex->getCapabilityName()));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
$dialog = id(new AphrontDialogView())
|
|
||||||
->setTitle($ex->getTitle())
|
|
||||||
->setClass('aphront-access-dialog')
|
|
||||||
->setUser($user)
|
|
||||||
->appendChild($content);
|
|
||||||
|
|
||||||
if ($list) {
|
|
||||||
$dialog->appendList($list);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->getRequest()->isAjax()) {
|
|
||||||
$dialog->addCancelButton('/', pht('Close'));
|
|
||||||
} else {
|
|
||||||
$dialog->addCancelButton('/', pht('OK'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$response = new AphrontDialogResponse();
|
|
||||||
$response->setDialog($dialog);
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Always log the unhandled exception.
|
|
||||||
phlog($ex);
|
|
||||||
|
|
||||||
$class = get_class($ex);
|
|
||||||
$message = $ex->getMessage();
|
|
||||||
|
|
||||||
if ($ex instanceof AphrontSchemaQueryException) {
|
|
||||||
$message .= "\n\n".pht(
|
|
||||||
"NOTE: This usually indicates that the MySQL schema has not been ".
|
|
||||||
"properly upgraded. Run '%s' to ensure your schema is up to date.",
|
|
||||||
'bin/storage upgrade');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PhabricatorEnv::getEnvConfig('phabricator.developer-mode')) {
|
|
||||||
$trace = id(new AphrontStackTraceView())
|
|
||||||
->setUser($user)
|
|
||||||
->setTrace($ex->getTrace());
|
|
||||||
} else {
|
|
||||||
$trace = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$content = phutil_tag(
|
|
||||||
'div',
|
|
||||||
array('class' => 'aphront-unhandled-exception'),
|
|
||||||
array(
|
|
||||||
phutil_tag('div', array('class' => 'exception-message'), $message),
|
|
||||||
$trace,
|
|
||||||
));
|
|
||||||
|
|
||||||
$dialog = new AphrontDialogView();
|
|
||||||
$dialog
|
|
||||||
->setTitle(pht('Unhandled Exception ("%s")', $class))
|
|
||||||
->setClass('aphront-exception-dialog')
|
|
||||||
->setUser($user)
|
|
||||||
->appendChild($content);
|
|
||||||
|
|
||||||
if ($this->getRequest()->isAjax()) {
|
|
||||||
$dialog->addCancelButton('/', pht('Close'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$response = new AphrontDialogResponse();
|
|
||||||
$response->setDialog($dialog);
|
|
||||||
$response->setHTTPResponseCode(500);
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function build404Controller() {
|
public function build404Controller() {
|
||||||
return array(new Phabricator404Controller(), array());
|
return array(new Phabricator404Controller(), array());
|
||||||
}
|
}
|
||||||
|
|
36
src/aphront/handler/AphrontRequestExceptionHandler.php
Normal file
36
src/aphront/handler/AphrontRequestExceptionHandler.php
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* React to an unhandled exception escaping request handling in a controller
|
||||||
|
* and convert it into a response.
|
||||||
|
*
|
||||||
|
* These handlers are generally used to render error pages, but they may
|
||||||
|
* also perform more specialized handling in situations where an error page
|
||||||
|
* is not appropriate.
|
||||||
|
*/
|
||||||
|
abstract class AphrontRequestExceptionHandler extends Phobject {
|
||||||
|
|
||||||
|
abstract public function getRequestExceptionHandlerPriority();
|
||||||
|
|
||||||
|
public function shouldLogException(
|
||||||
|
AphrontRequest $request,
|
||||||
|
Exception $ex) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract public function canHandleRequestException(
|
||||||
|
AphrontRequest $request,
|
||||||
|
Exception $ex);
|
||||||
|
|
||||||
|
abstract public function handleRequestException(
|
||||||
|
AphrontRequest $request,
|
||||||
|
Exception $ex);
|
||||||
|
|
||||||
|
final public static function getAllHandlers() {
|
||||||
|
return id(new PhutilClassMapQuery())
|
||||||
|
->setAncestorClass(__CLASS__)
|
||||||
|
->setSortMethod('getRequestExceptionHandlerPriority')
|
||||||
|
->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorAjaxRequestExceptionHandler
|
||||||
|
extends PhabricatorRequestExceptionHandler {
|
||||||
|
|
||||||
|
public function getRequestExceptionHandlerPriority() {
|
||||||
|
return 110000;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRequestExceptionHandlerDescription() {
|
||||||
|
return pht('Responds to requests made by AJAX clients.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canHandleRequestException(
|
||||||
|
AphrontRequest $request,
|
||||||
|
Exception $ex) {
|
||||||
|
// For non-workflow requests, return a Ajax response.
|
||||||
|
return ($request->isAjax() && !$request->isWorkflow());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleRequestException(
|
||||||
|
AphrontRequest $request,
|
||||||
|
Exception $ex) {
|
||||||
|
|
||||||
|
// Log these; they don't get shown on the client and can be difficult
|
||||||
|
// to debug.
|
||||||
|
phlog($ex);
|
||||||
|
|
||||||
|
$response = new AphrontAjaxResponse();
|
||||||
|
$response->setError(
|
||||||
|
array(
|
||||||
|
'code' => get_class($ex),
|
||||||
|
'info' => $ex->getMessage(),
|
||||||
|
));
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorConduitRequestExceptionHandler
|
||||||
|
extends PhabricatorRequestExceptionHandler {
|
||||||
|
|
||||||
|
public function getRequestExceptionHandlerPriority() {
|
||||||
|
return 100000;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRequestExceptionHandlerDescription() {
|
||||||
|
return pht('Responds to requests made by Conduit clients.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canHandleRequestException(
|
||||||
|
AphrontRequest $request,
|
||||||
|
Exception $ex) {
|
||||||
|
return $request->isConduit();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleRequestException(
|
||||||
|
AphrontRequest $request,
|
||||||
|
Exception $ex) {
|
||||||
|
|
||||||
|
$response = id(new ConduitAPIResponse())
|
||||||
|
->setErrorCode(get_class($ex))
|
||||||
|
->setErrorInfo($ex->getMessage());
|
||||||
|
|
||||||
|
return id(new AphrontJSONResponse())
|
||||||
|
->setAddJSONShield(false)
|
||||||
|
->setContent($response->toDictionary());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorDefaultRequestExceptionHandler
|
||||||
|
extends PhabricatorRequestExceptionHandler {
|
||||||
|
|
||||||
|
public function getRequestExceptionHandlerPriority() {
|
||||||
|
return 900000;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRequestExceptionHandlerDescription() {
|
||||||
|
return pht('Handles all other exceptions.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canHandleRequestException(
|
||||||
|
AphrontRequest $request,
|
||||||
|
Exception $ex) {
|
||||||
|
|
||||||
|
if (!$this->isPhabricatorSite($request)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleRequestException(
|
||||||
|
AphrontRequest $request,
|
||||||
|
Exception $ex) {
|
||||||
|
|
||||||
|
$viewer = $this->getViewer($request);
|
||||||
|
|
||||||
|
// Always log the unhandled exception.
|
||||||
|
phlog($ex);
|
||||||
|
|
||||||
|
$class = get_class($ex);
|
||||||
|
$message = $ex->getMessage();
|
||||||
|
|
||||||
|
if ($ex instanceof AphrontSchemaQueryException) {
|
||||||
|
$message .= "\n\n".pht(
|
||||||
|
"NOTE: This usually indicates that the MySQL schema has not been ".
|
||||||
|
"properly upgraded. Run '%s' to ensure your schema is up to date.",
|
||||||
|
'bin/storage upgrade');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PhabricatorEnv::getEnvConfig('phabricator.developer-mode')) {
|
||||||
|
$trace = id(new AphrontStackTraceView())
|
||||||
|
->setUser($viewer)
|
||||||
|
->setTrace($ex->getTrace());
|
||||||
|
} else {
|
||||||
|
$trace = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = phutil_tag(
|
||||||
|
'div',
|
||||||
|
array('class' => 'aphront-unhandled-exception'),
|
||||||
|
array(
|
||||||
|
phutil_tag('div', array('class' => 'exception-message'), $message),
|
||||||
|
$trace,
|
||||||
|
));
|
||||||
|
|
||||||
|
$dialog = new AphrontDialogView();
|
||||||
|
$dialog
|
||||||
|
->setTitle(pht('Unhandled Exception ("%s")', $class))
|
||||||
|
->setClass('aphront-exception-dialog')
|
||||||
|
->setUser($viewer)
|
||||||
|
->appendChild($content);
|
||||||
|
|
||||||
|
if ($request->isAjax()) {
|
||||||
|
$dialog->addCancelButton('/', pht('Close'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return id(new AphrontDialogResponse())
|
||||||
|
->setDialog($dialog)
|
||||||
|
->setHTTPResponseCode(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorHighSecurityRequestExceptionHandler
|
||||||
|
extends PhabricatorRequestExceptionHandler {
|
||||||
|
|
||||||
|
public function getRequestExceptionHandlerPriority() {
|
||||||
|
return 310000;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRequestExceptionHandlerDescription() {
|
||||||
|
return pht(
|
||||||
|
'Handles high security exceptions which occur when a user needs '.
|
||||||
|
'to present MFA credentials to take an action.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canHandleRequestException(
|
||||||
|
AphrontRequest $request,
|
||||||
|
Exception $ex) {
|
||||||
|
|
||||||
|
if (!$this->isPhabricatorSite($request)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ($ex instanceof PhabricatorAuthHighSecurityRequiredException);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleRequestException(
|
||||||
|
AphrontRequest $request,
|
||||||
|
Exception $ex) {
|
||||||
|
|
||||||
|
$viewer = $this->getViewer($request);
|
||||||
|
|
||||||
|
$form = id(new PhabricatorAuthSessionEngine())->renderHighSecurityForm(
|
||||||
|
$ex->getFactors(),
|
||||||
|
$ex->getFactorValidationResults(),
|
||||||
|
$viewer,
|
||||||
|
$request);
|
||||||
|
|
||||||
|
$dialog = id(new AphrontDialogView())
|
||||||
|
->setUser($viewer)
|
||||||
|
->setTitle(pht('Entering High Security'))
|
||||||
|
->setShortTitle(pht('Security Checkpoint'))
|
||||||
|
->setWidth(AphrontDialogView::WIDTH_FORM)
|
||||||
|
->addHiddenInput(AphrontRequest::TYPE_HISEC, true)
|
||||||
|
->setErrors(
|
||||||
|
array(
|
||||||
|
pht(
|
||||||
|
'You are taking an action which requires you to enter '.
|
||||||
|
'high security.'),
|
||||||
|
))
|
||||||
|
->appendParagraph(
|
||||||
|
pht(
|
||||||
|
'High security mode helps protect your account from security '.
|
||||||
|
'threats, like session theft or someone messing with your stuff '.
|
||||||
|
'while you\'re grabbing a coffee. To enter high security mode, '.
|
||||||
|
'confirm your credentials.'))
|
||||||
|
->appendChild($form->buildLayoutView())
|
||||||
|
->appendParagraph(
|
||||||
|
pht(
|
||||||
|
'Your account will remain in high security mode for a short '.
|
||||||
|
'period of time. When you are finished taking sensitive '.
|
||||||
|
'actions, you should leave high security.'))
|
||||||
|
->setSubmitURI($request->getPath())
|
||||||
|
->addCancelButton($ex->getCancelURI())
|
||||||
|
->addSubmitButton(pht('Enter High Security'));
|
||||||
|
|
||||||
|
$request_parameters = $request->getPassthroughRequestParameters(
|
||||||
|
$respect_quicksand = true);
|
||||||
|
foreach ($request_parameters as $key => $value) {
|
||||||
|
$dialog->addHiddenInput($key, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $dialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorPolicyRequestExceptionHandler
|
||||||
|
extends PhabricatorRequestExceptionHandler {
|
||||||
|
|
||||||
|
public function getRequestExceptionHandlerPriority() {
|
||||||
|
return 320000;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRequestExceptionHandlerDescription() {
|
||||||
|
return pht(
|
||||||
|
'Handles policy exceptions which occur when a user tries to '.
|
||||||
|
'do something they do not have permission to do.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canHandleRequestException(
|
||||||
|
AphrontRequest $request,
|
||||||
|
Exception $ex) {
|
||||||
|
|
||||||
|
if (!$this->isPhabricatorSite($request)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ($ex instanceof PhabricatorPolicyException);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleRequestException(
|
||||||
|
AphrontRequest $request,
|
||||||
|
Exception $ex) {
|
||||||
|
|
||||||
|
$viewer = $this->getViewer($request);
|
||||||
|
|
||||||
|
if (!$viewer->isLoggedIn()) {
|
||||||
|
// If the user isn't logged in, just give them a login form. This is
|
||||||
|
// probably a generally more useful response than a policy dialog that
|
||||||
|
// they have to click through to get a login form.
|
||||||
|
//
|
||||||
|
// Possibly we should add a header here like "you need to login to see
|
||||||
|
// the thing you are trying to look at".
|
||||||
|
$auth_app_class = 'PhabricatorAuthApplication';
|
||||||
|
$auth_app = PhabricatorApplication::getByClass($auth_app_class);
|
||||||
|
|
||||||
|
return id(new PhabricatorAuthStartController())
|
||||||
|
->setRequest($request)
|
||||||
|
->setCurrentApplication($auth_app)
|
||||||
|
->handleRequest($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = array(
|
||||||
|
phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'aphront-policy-rejection',
|
||||||
|
),
|
||||||
|
$ex->getRejection()),
|
||||||
|
);
|
||||||
|
|
||||||
|
$list = null;
|
||||||
|
if ($ex->getCapabilityName()) {
|
||||||
|
$list = $ex->getMoreInfo();
|
||||||
|
foreach ($list as $key => $item) {
|
||||||
|
$list[$key] = $item;
|
||||||
|
}
|
||||||
|
|
||||||
|
$content[] = phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'aphront-capability-details',
|
||||||
|
),
|
||||||
|
pht('Users with the "%s" capability:', $ex->getCapabilityName()));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$dialog = id(new AphrontDialogView())
|
||||||
|
->setTitle($ex->getTitle())
|
||||||
|
->setClass('aphront-access-dialog')
|
||||||
|
->setUser($viewer)
|
||||||
|
->appendChild($content);
|
||||||
|
|
||||||
|
if ($list) {
|
||||||
|
$dialog->appendList($list);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->isAjax()) {
|
||||||
|
$dialog->addCancelButton('/', pht('Close'));
|
||||||
|
} else {
|
||||||
|
$dialog->addCancelButton('/', pht('OK'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $dialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorRateLimitRequestExceptionHandler
|
||||||
|
extends PhabricatorRequestExceptionHandler {
|
||||||
|
|
||||||
|
public function getRequestExceptionHandlerPriority() {
|
||||||
|
return 300000;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRequestExceptionHandlerDescription() {
|
||||||
|
return pht(
|
||||||
|
'Handles action rate limiting exceptions which occur when a user '.
|
||||||
|
'does something too frequently.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canHandleRequestException(
|
||||||
|
AphrontRequest $request,
|
||||||
|
Exception $ex) {
|
||||||
|
|
||||||
|
if (!$this->isPhabricatorSite($request)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ($ex instanceof PhabricatorSystemActionRateLimitException);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleRequestException(
|
||||||
|
AphrontRequest $request,
|
||||||
|
Exception $ex) {
|
||||||
|
|
||||||
|
$viewer = $this->getViewer($request);
|
||||||
|
|
||||||
|
return id(new AphrontDialogView())
|
||||||
|
->setTitle(pht('Slow Down!'))
|
||||||
|
->setUser($viewer)
|
||||||
|
->setErrors(array(pht('You are being rate limited.')))
|
||||||
|
->appendParagraph($ex->getMessage())
|
||||||
|
->appendParagraph($ex->getRateExplanation())
|
||||||
|
->addCancelButton('/', pht('Okaaaaaaaaaaaaaay...'));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
26
src/aphront/handler/PhabricatorRequestExceptionHandler.php
Normal file
26
src/aphront/handler/PhabricatorRequestExceptionHandler.php
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class PhabricatorRequestExceptionHandler
|
||||||
|
extends AphrontRequestExceptionHandler {
|
||||||
|
|
||||||
|
protected function isPhabricatorSite(AphrontRequest $request) {
|
||||||
|
$site = $request->getSite();
|
||||||
|
if (!$site) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ($site instanceof PhabricatorSite);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getViewer(AphrontRequest $request) {
|
||||||
|
$viewer = $request->getUser();
|
||||||
|
|
||||||
|
if ($viewer) {
|
||||||
|
return $viewer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we hit an exception very early, we won't have a user yet.
|
||||||
|
return new PhabricatorUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -41,7 +41,7 @@ final class PhabricatorConfigEdgeModule extends PhabricatorConfigModule {
|
||||||
|
|
||||||
return id(new PHUIObjectBoxView())
|
return id(new PHUIObjectBoxView())
|
||||||
->setHeaderText(pht('Edge Types'))
|
->setHeaderText(pht('Edge Types'))
|
||||||
->appendChild($table);
|
->setTable($table);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ final class PhabricatorConfigPHIDModule extends PhabricatorConfigModule {
|
||||||
|
|
||||||
return id(new PHUIObjectBoxView())
|
return id(new PHUIObjectBoxView())
|
||||||
->setHeaderText(pht('PHID Types'))
|
->setHeaderText(pht('PHID Types'))
|
||||||
->appendChild($table);
|
->setTable($table);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorConfigRequestExceptionHandlerModule
|
||||||
|
extends PhabricatorConfigModule {
|
||||||
|
|
||||||
|
public function getModuleKey() {
|
||||||
|
return 'exception-handler';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getModuleName() {
|
||||||
|
return pht('Exception Handlers');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderModuleStatus(AphrontRequest $request) {
|
||||||
|
$viewer = $request->getViewer();
|
||||||
|
|
||||||
|
$handlers = AphrontRequestExceptionHandler::getAllHandlers();
|
||||||
|
|
||||||
|
$rows = array();
|
||||||
|
foreach ($handlers as $key => $handler) {
|
||||||
|
$rows[] = array(
|
||||||
|
$handler->getRequestExceptionHandlerPriority(),
|
||||||
|
$key,
|
||||||
|
$handler->getRequestExceptionHandlerDescription(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$table = id(new AphrontTableView($rows))
|
||||||
|
->setHeaders(
|
||||||
|
array(
|
||||||
|
pht('Priority'),
|
||||||
|
pht('Class'),
|
||||||
|
pht('Description'),
|
||||||
|
))
|
||||||
|
->setColumnClasses(
|
||||||
|
array(
|
||||||
|
null,
|
||||||
|
'pri',
|
||||||
|
'wide',
|
||||||
|
));
|
||||||
|
|
||||||
|
return id(new PHUIObjectBoxView())
|
||||||
|
->setHeaderText(pht('Exception Handlers'))
|
||||||
|
->setTable($table);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -40,7 +40,7 @@ final class PhabricatorConfigSiteModule extends PhabricatorConfigModule {
|
||||||
|
|
||||||
return id(new PHUIObjectBoxView())
|
return id(new PHUIObjectBoxView())
|
||||||
->setHeaderText(pht('Sites'))
|
->setHeaderText(pht('Sites'))
|
||||||
->appendChild($table);
|
->setTable($table);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue