diff --git a/src/aphront/configuration/AphrontDefaultApplicationConfiguration.php b/src/aphront/configuration/AphrontDefaultApplicationConfiguration.php index d175a175ad..a950a620a6 100644 --- a/src/aphront/configuration/AphrontDefaultApplicationConfiguration.php +++ b/src/aphront/configuration/AphrontDefaultApplicationConfiguration.php @@ -1,386 +1,386 @@ <?php /** * @group aphront */ class AphrontDefaultApplicationConfiguration extends AphrontApplicationConfiguration { public function __construct() { } public function getApplicationName() { return 'aphront-default'; } public function getURIMap() { return $this->getResourceURIMapRules() + array( '/(?:(?P<filter>(?:jump))/)?' => 'PhabricatorDirectoryMainController', '/typeahead/' => array( 'common/(?P<type>\w+)/' => 'PhabricatorTypeaheadCommonDatasourceController', ), '/login/' => array( '' => 'PhabricatorLoginController', 'email/' => 'PhabricatorEmailLoginController', 'etoken/(?P<token>\w+)/' => 'PhabricatorEmailTokenController', 'refresh/' => 'PhabricatorRefreshCSRFController', 'validate/' => 'PhabricatorLoginValidateController', 'mustverify/' => 'PhabricatorMustVerifyEmailController', ), '/logout/' => 'PhabricatorLogoutController', '/oauth/' => array( '(?P<provider>\w+)/' => array( 'login/' => 'PhabricatorOAuthLoginController', 'diagnose/' => 'PhabricatorOAuthDiagnosticsController', 'unlink/' => 'PhabricatorOAuthUnlinkController', ), ), '/ldap/' => array( 'login/' => 'PhabricatorLDAPLoginController', 'unlink/' => 'PhabricatorLDAPUnlinkController', ), '/oauthserver/' => array( 'auth/' => 'PhabricatorOAuthServerAuthController', 'test/' => 'PhabricatorOAuthServerTestController', 'token/' => 'PhabricatorOAuthServerTokenController', 'clientauthorization/' => array( '' => 'PhabricatorOAuthClientAuthorizationListController', 'delete/(?P<phid>[^/]+)/' => 'PhabricatorOAuthClientAuthorizationDeleteController', 'edit/(?P<phid>[^/]+)/' => 'PhabricatorOAuthClientAuthorizationEditController', ), 'client/' => array( '' => 'PhabricatorOAuthClientListController', 'create/' => 'PhabricatorOAuthClientEditController', 'delete/(?P<phid>[^/]+)/' => 'PhabricatorOAuthClientDeleteController', 'edit/(?P<phid>[^/]+)/' => 'PhabricatorOAuthClientEditController', 'view/(?P<phid>[^/]+)/' => 'PhabricatorOAuthClientViewController', ), ), '/xhprof/' => array( 'list/(?P<view>[^/]+)/' => 'PhabricatorXHProfSampleListController', 'profile/(?P<phid>[^/]+)/' => 'PhabricatorXHProfProfileController', ), '/~/' => array( '' => 'DarkConsoleController', 'data/(?P<key>[^/]+)/' => 'DarkConsoleDataController', ), '/search/' => array( '' => 'PhabricatorSearchController', '(?P<key>[^/]+)/' => 'PhabricatorSearchController', 'attach/(?P<phid>[^/]+)/(?P<type>\w+)/(?:(?P<action>\w+)/)?' => 'PhabricatorSearchAttachController', 'select/(?P<type>\w+)/' => 'PhabricatorSearchSelectController', 'index/(?P<phid>[^/]+)/' => 'PhabricatorSearchIndexController', ), '/status/' => 'PhabricatorStatusController', '/help/' => array( 'keyboardshortcut/' => 'PhabricatorHelpKeyboardShortcutController', ), '/chatlog/' => array( '' => 'PhabricatorChatLogChannelListController', 'channel/(?P<channel>[^/]+)/' => 'PhabricatorChatLogChannelLogController', ), '/notification/' => array( '(?:(?P<filter>all|unread)/)?' => 'PhabricatorNotificationListController', 'panel/' => 'PhabricatorNotificationPanelController', 'individual/' => 'PhabricatorNotificationIndividualController', 'status/' => 'PhabricatorNotificationStatusController', 'clear/' => 'PhabricatorNotificationClearController', ), '/phortune/' => array( 'stripe/' => array( 'testpaymentform/' => 'PhortuneStripeTestPaymentFormController', ), ), ); } protected function getResourceURIMapRules() { return array( '/res/' => array( '(?P<package>pkg/)?'. '(?P<hash>[a-f0-9]{8})/'. '(?P<path>.+\.(?:css|js|jpg|png|swf|gif))' => 'CelerityPhabricatorResourceController', ), ); } public function buildRequest() { $request = new AphrontRequest($this->getHost(), $this->getPath()); $request->setRequestData($_GET + $_POST); $request->setApplicationConfiguration($this); 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()) ->setContent($response->toDictionary()); } // For non-workflow requests, return a Ajax response. if ($request->isAjax() && !$request->isJavelinWorkflow()) { $response = new AphrontAjaxResponse(); $response->setError( array( 'code' => get_class($ex), 'info' => $ex->getMessage(), )); return $response; } $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); $user = $request->getUser(); if (!$user) { // If we hit an exception very early, we won't have a user. $user = new PhabricatorUser(); } 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 PhabricatorLoginController($request); return $login_controller->processRequest(); } $content = hsprintf( '<div class="aphront-policy-exception">%s</div>', $ex->getMessage()); $dialog = new AphrontDialogView(); $dialog ->setTitle( $is_serious ? 'Access Denied' : "You Shall Not Pass") ->setClass('aphront-access-dialog') ->setUser($user) ->appendChild($content); if ($this->getRequest()->isAjax()) { $dialog->addCancelButton('/', 'Close'); } else { $dialog->addCancelButton('/', $is_serious ? 'OK' : 'Away With Thee'); } $response = new AphrontDialogResponse(); $response->setDialog($dialog); return $response; } if ($ex instanceof AphrontUsageException) { $error = new AphrontErrorView(); - $error->setTitle(phutil_escape_html($ex->getTitle())); + $error->setTitle($ex->getTitle()); $error->appendChild($ex->getMessage()); $view = new PhabricatorStandardPageView(); $view->setRequest($this->getRequest()); $view->appendChild($error); $response = new AphrontWebpageResponse(); $response->setContent($view->render()); return $response; } // Always log the unhandled exception. phlog($ex); - $class = phutil_escape_html(get_class($ex)); + $class = get_class($ex); $message = phutil_escape_html($ex->getMessage()); if ($ex instanceof AphrontQuerySchemaException) { $message .= "\n\n". "NOTE: This usually indicates that the MySQL schema has not been ". "properly upgraded. Run 'bin/storage upgrade' to ensure your ". "schema is up to date."; } if (PhabricatorEnv::getEnvConfig('phabricator.developer-mode')) { $trace = $this->renderStackTrace($ex->getTrace(), $user); } else { $trace = null; } $content = '<div class="aphront-unhandled-exception">'. '<div class="exception-message">'.$message.'</div>'. $trace. '</div>'; $dialog = new AphrontDialogView(); $dialog ->setTitle('Unhandled Exception ("'.$class.'")') ->setClass('aphront-exception-dialog') ->setUser($user) ->appendChild($content); if ($this->getRequest()->isAjax()) { $dialog->addCancelButton('/', 'Close'); } $response = new AphrontDialogResponse(); $response->setDialog($dialog); return $response; } public function willSendResponse(AphrontResponse $response) { return $response; } public function build404Controller() { return array(new Phabricator404Controller($this->getRequest()), array()); } public function buildRedirectController($uri) { return array( new PhabricatorRedirectController($this->getRequest()), array( 'uri' => $uri, )); } private function renderStackTrace($trace, PhabricatorUser $user) { $libraries = PhutilBootloader::getInstance()->getAllLibraries(); // TODO: Make this configurable? $path = 'https://secure.phabricator.com/diffusion/%s/browse/master/src/'; $callsigns = array( 'arcanist' => 'ARC', 'phutil' => 'PHU', 'phabricator' => 'P', ); $rows = array(); $depth = count($trace); foreach ($trace as $part) { $lib = null; $file = idx($part, 'file'); $relative = $file; foreach ($libraries as $library) { $root = phutil_get_library_root($library); if (Filesystem::isDescendant($file, $root)) { $lib = $library; $relative = Filesystem::readablePath($file, $root); break; } } $where = ''; if (isset($part['class'])) { $where .= $part['class'].'::'; } if (isset($part['function'])) { $where .= $part['function'].'()'; } if ($file) { if (isset($callsigns[$lib])) { $attrs = array('title' => $file); try { $attrs['href'] = $user->loadEditorLink( '/src/'.$relative, $part['line'], $callsigns[$lib]); } catch (Exception $ex) { // The database can be inaccessible. } if (empty($attrs['href'])) { $attrs['href'] = sprintf($path, $callsigns[$lib]). str_replace(DIRECTORY_SEPARATOR, '/', $relative). '$'.$part['line']; $attrs['target'] = '_blank'; } $file_name = phutil_tag( 'a', $attrs, $relative); } else { $file_name = phutil_tag( 'span', array( 'title' => $file, ), $relative); } $file_name = $file_name.' : '.(int)$part['line']; } else { $file_name = '<em>(Internal)</em>'; } $rows[] = array( $depth--, phutil_escape_html($lib), $file_name, phutil_escape_html($where), ); } $table = new AphrontTableView($rows); $table->setHeaders( array( 'Depth', 'Library', 'File', 'Where', )); $table->setColumnClasses( array( 'n', '', '', 'wide', )); return '<div class="exception-trace">'. '<div class="exception-trace-header">Stack Trace</div>'. $table->render(). '</div>'; } } diff --git a/src/applications/oauthserver/controller/client/PhabricatorOAuthClientDeleteController.php b/src/applications/oauthserver/controller/client/PhabricatorOAuthClientDeleteController.php index cb893c78ea..49601ce66f 100644 --- a/src/applications/oauthserver/controller/client/PhabricatorOAuthClientDeleteController.php +++ b/src/applications/oauthserver/controller/client/PhabricatorOAuthClientDeleteController.php @@ -1,49 +1,48 @@ <?php /** * @group oauthserver */ final class PhabricatorOAuthClientDeleteController extends PhabricatorOAuthClientBaseController { public function processRequest() { $phid = $this->getClientPHID(); $title = 'Delete OAuth Client'; $request = $this->getRequest(); $current_user = $request->getUser(); $client = id(new PhabricatorOAuthServerClient()) ->loadOneWhere('phid = %s', $phid); if (empty($client)) { return new Aphront404Response(); } if ($client->getCreatorPHID() != $current_user->getPHID()) { $message = 'Access denied to client with phid '.$phid.'. '. 'Only the user who created the client has permission to '. 'delete the client.'; return id(new Aphront403Response()) ->setForbiddenText($message); } if ($request->isFormPost()) { $client->delete(); return id(new AphrontRedirectResponse()) ->setURI('/oauthserver/client/?deleted=1'); } - $client_name = phutil_escape_html($client->getName()); - $title .= ' '.$client_name; + $title .= ' '.$client->getName(); $dialog = new AphrontDialogView(); $dialog->setUser($current_user); $dialog->setTitle($title); $dialog->appendChild( '<p>Are you sure you want to delete this client?</p>' ); $dialog->addSubmitButton(); $dialog->addCancelButton($client->getEditURI()); return id(new AphrontDialogResponse())->setDialog($dialog); } } diff --git a/src/applications/oauthserver/controller/client/PhabricatorOAuthClientListController.php b/src/applications/oauthserver/controller/client/PhabricatorOAuthClientListController.php index 51104ae880..b8d6d65907 100644 --- a/src/applications/oauthserver/controller/client/PhabricatorOAuthClientListController.php +++ b/src/applications/oauthserver/controller/client/PhabricatorOAuthClientListController.php @@ -1,137 +1,135 @@ <?php /** * @group oauthserver */ final class PhabricatorOAuthClientListController extends PhabricatorOAuthClientBaseController { public function getFilter() { return 'client'; } public function processRequest() { $title = 'OAuth Clients'; $request = $this->getRequest(); $current_user = $request->getUser(); $offset = $request->getInt('offset', 0); $page_size = 100; $pager = new AphrontPagerView(); $request_uri = $request->getRequestURI(); $pager->setURI($request_uri, 'offset'); $pager->setPageSize($page_size); $pager->setOffset($offset); $query = new PhabricatorOAuthServerClientQuery(); $query->withCreatorPHIDs(array($current_user->getPHID())); $clients = $query->executeWithOffsetPager($pager); $rows = array(); $rowc = array(); $highlight = $this->getHighlightPHIDs(); foreach ($clients as $client) { $row = array( phutil_tag( 'a', array( 'href' => $client->getViewURI(), ), $client->getName() ), $client->getPHID(), $client->getSecret(), phutil_tag( 'a', array( 'href' => $client->getRedirectURI(), ), $client->getRedirectURI() ), phutil_tag( 'a', array( 'class' => 'small button grey', 'href' => $client->getEditURI(), ), 'Edit' ), ); $rows[] = $row; if (isset($highlight[$client->getPHID()])) { $rowc[] = 'highlighted'; } else { $rowc[] = ''; } } $panel = $this->buildClientList($rows, $rowc, $title); return $this->buildStandardPageResponse( array( $this->getNoticeView(), $panel->appendChild($pager) ), array('title' => $title) ); } private function buildClientList($rows, $rowc, $title) { $table = new AphrontTableView($rows); $table->setRowClasses($rowc); $table->setHeaders( array( 'Client', 'ID', 'Secret', 'Redirect URI', '', )); $table->setColumnClasses( array( '', '', '', '', 'action', )); if (empty($rows)) { $table->setNoDataString( 'You have not created any clients for this OAuthServer.' ); } $panel = new AphrontPanelView(); $panel->appendChild($table); $panel->setHeader($title); return $panel; } private function getNoticeView() { $edited = $this->getRequest()->getStr('edited'); $new = $this->getRequest()->getStr('new'); $deleted = $this->getRequest()->getBool('deleted'); if ($edited) { - $edited = phutil_escape_html($edited); $title = 'Successfully edited client with id '.$edited.'.'; } else if ($new) { - $new = phutil_escape_html($new); $title = 'Successfully created client with id '.$new.'.'; } else if ($deleted) { $title = 'Successfully deleted client.'; } else { $title = null; } if ($title) { $view = new AphrontErrorView(); $view->setTitle($title); $view->setSeverity(AphrontErrorView::SEVERITY_NOTICE); } else { $view = null; } return $view; } } diff --git a/src/applications/oauthserver/controller/clientauthorization/PhabricatorOAuthClientAuthorizationDeleteController.php b/src/applications/oauthserver/controller/clientauthorization/PhabricatorOAuthClientAuthorizationDeleteController.php index 94c9839d79..11b66df39a 100644 --- a/src/applications/oauthserver/controller/clientauthorization/PhabricatorOAuthClientAuthorizationDeleteController.php +++ b/src/applications/oauthserver/controller/clientauthorization/PhabricatorOAuthClientAuthorizationDeleteController.php @@ -1,59 +1,57 @@ <?php /** * @group oauthserver */ final class PhabricatorOAuthClientAuthorizationDeleteController extends PhabricatorOAuthClientAuthorizationBaseController { public function processRequest() { $phid = $this->getAuthorizationPHID(); $title = 'Delete OAuth Client Authorization'; $request = $this->getRequest(); $current_user = $request->getUser(); $authorization = id(new PhabricatorOAuthClientAuthorization()) ->loadOneWhere('phid = %s', $phid); if (empty($authorization)) { return new Aphront404Response(); } if ($authorization->getUserPHID() != $current_user->getPHID()) { $message = 'Access denied to client authorization with phid '.$phid.'. '. 'Only the user who authorized the client has permission to '. 'delete the authorization.'; return id(new Aphront403Response()) ->setForbiddenText($message); } if ($request->isFormPost()) { $authorization->delete(); return id(new AphrontRedirectResponse()) ->setURI('/oauthserver/clientauthorization/?notice=deleted'); } $client_phid = $authorization->getClientPHID(); $client = id(new PhabricatorOAuthServerClient()) ->loadOneWhere('phid = %s', $client_phid); if ($client) { - $client_name = phutil_escape_html($client->getName()); - $title .= ' for '.$client_name; + $title .= ' for '.$client->getName(); } else { // the client does not exist so token is dead already (but // let's let the user clean this up anyway in that case) - $client_name = ''; } $dialog = new AphrontDialogView(); $dialog->setUser($current_user); $dialog->setTitle($title); $dialog->appendChild( '<p>Are you sure you want to delete this client authorization?</p>' ); $dialog->addSubmitButton(); $dialog->addCancelButton($authorization->getEditURI()); return id(new AphrontDialogResponse())->setDialog($dialog); } } diff --git a/src/applications/oauthserver/controller/clientauthorization/PhabricatorOAuthClientAuthorizationListController.php b/src/applications/oauthserver/controller/clientauthorization/PhabricatorOAuthClientAuthorizationListController.php index c3b0a927af..d45e4dc96d 100644 --- a/src/applications/oauthserver/controller/clientauthorization/PhabricatorOAuthClientAuthorizationListController.php +++ b/src/applications/oauthserver/controller/clientauthorization/PhabricatorOAuthClientAuthorizationListController.php @@ -1,158 +1,157 @@ <?php /** * @group oauthserver */ final class PhabricatorOAuthClientAuthorizationListController extends PhabricatorOAuthClientAuthorizationBaseController { protected function getFilter() { return 'clientauthorization'; } public function processRequest() { $title = 'OAuth Client Authorizations'; $request = $this->getRequest(); $current_user = $request->getUser(); $offset = $request->getInt('offset', 0); $page_size = 100; $pager = new AphrontPagerView(); $request_uri = $request->getRequestURI(); $pager->setURI($request_uri, 'offset'); $pager->setPageSize($page_size); $pager->setOffset($offset); $query = new PhabricatorOAuthClientAuthorizationQuery(); $query->withUserPHIDs(array($current_user->getPHID())); $authorizations = $query->executeWithOffsetPager($pager); $client_authorizations = mpull($authorizations, null, 'getClientPHID'); $client_phids = array_keys($client_authorizations); if ($client_phids) { $clients = id(new PhabricatorOAuthServerClient()) ->loadAllWhere('phid in (%Ls)', $client_phids); } else { $clients = array(); } $client_dict = mpull($clients, null, 'getPHID'); $rows = array(); $rowc = array(); $highlight = $this->getHighlightPHIDs(); foreach ($client_authorizations as $client_phid => $authorization) { $client = $client_dict[$client_phid]; $created = phabricator_datetime($authorization->getDateCreated(), $current_user); $updated = phabricator_datetime($authorization->getDateModified(), $current_user); $scope_doc_href = PhabricatorEnv::getDoclink( 'article/Using_the_Phabricator_OAuth_Server.html#scopes' ); $row = array( phutil_tag( 'a', array( 'href' => $client->getViewURI(), ), $client->getName() ), phutil_tag( 'a', array( 'href' => $scope_doc_href, ), $authorization->getScopeString() ), phabricator_datetime( $authorization->getDateCreated(), $current_user ), phabricator_datetime( $authorization->getDateModified(), $current_user ), phutil_tag( 'a', array( 'class' => 'small button grey', 'href' => $authorization->getEditURI(), ), 'Edit' ), ); $rows[] = $row; if (isset($highlight[$authorization->getPHID()])) { $rowc[] = 'highlighted'; } else { $rowc[] = ''; } } $panel = $this->buildClientAuthorizationList($rows, $rowc, $title); return $this->buildStandardPageResponse( array( $this->getNoticeView(), $panel->appendChild($pager), ), array('title' => $title) ); } private function buildClientAuthorizationList($rows, $rowc, $title) { $table = new AphrontTableView($rows); $table->setRowClasses($rowc); $table->setHeaders( array( 'Client', 'Scope', 'Created', 'Updated', '', )); $table->setColumnClasses( array( 'wide pri', '', '', '', 'action', )); if (empty($rows)) { $table->setNoDataString( 'You have not authorized any clients for this OAuthServer.' ); } $panel = new AphrontPanelView(); $panel->appendChild($table); $panel->setHeader($title); return $panel; } private function getNoticeView() { $edited = $this->getRequest()->getStr('edited'); $deleted = $this->getRequest()->getBool('deleted'); if ($edited) { - $edited = phutil_escape_html($edited); $title = 'Successfully edited client authorization.'; } else if ($deleted) { $title = 'Successfully deleted client authorization.'; } else { $title = null; } if ($title) { $view = new AphrontErrorView(); $view->setTitle($title); $view->setSeverity(AphrontErrorView::SEVERITY_NOTICE); } else { $view = null; } return $view; } }