From e46826ad364d5060cbb9490aef4c6af0c9f8cac6 Mon Sep 17 00:00:00 2001 From: epriestley Date: Thu, 10 Jul 2014 10:18:10 -0700 Subject: [PATCH] Introduce CAN_EDIT for ExternalAccount, and make CAN_VIEW more liberal Summary: Fixes T3732. Ref T1205. Ref T3116. External accounts (like emails used as identities, Facebook accounts, LDAP accounts, etc.) are stored in "ExternalAccount" objects. Currently, we have a very restrictive `CAN_VIEW` policy for ExternalAccounts, to add an extra layer of protection to make sure users can't use them in unintended ways. For example, it would be bad if a user could link their Phabricator account to a Facebook account without proper authentication. All of the controllers which do sensitive things have checks anyway, but a restrictive CAN_VIEW provided an extra layer of protection. Se T3116 for some discussion. However, this means that when grey/external users take actions (via email, or via applications like Legalpad) other users can't load the account handles and can't see anything about the actor (they just see "Restricted External Account" or similar). Balancing these concerns is mostly about not making a huge mess while doing it. This seems like a reasonable approach: - Add `CAN_EDIT` on these objects. - Make that very restricted, but open up `CAN_VIEW`. - Require `CAN_EDIT` any time we're going to do something authentication/identity related. This is slightly easier to get wrong (forget CAN_EDIT) than other approaches, but pretty simple, and we always have extra checks in place anyway -- this is just a safety net. I'm not quite sure how we should identify external accounts, so for now we're just rendering "Email User" or similar -- clearly not a bug, but not identifying. We can figure out what to render in the long term elsewhere. Test Plan: - Viewed external accounts. - Linked an external account. - Refreshed an external account. - Edited profile picture. - Viewed sessions panel. - Published a bunch of stuff to Asana/JIRA. - Legalpad signature page now shows external accounts. {F171595} Reviewers: chad, btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T3732, T1205, T3116 Differential Revision: https://secure.phabricator.com/D9767 --- resources/celerity/map.php | 338 +++++++++--------- .../controller/PhabricatorAuthController.php | 9 +- ...abricatorAuthManagementRefreshWorkflow.php | 7 +- .../query/PhabricatorExternalAccountQuery.php | 10 + .../landing/DifferentialLandingToGitHub.php | 5 + .../bridge/DoorkeeperBridgeAsana.php | 5 + .../bridge/DoorkeeperBridgeJIRA.php | 5 + .../option/PhabricatorAsanaConfigOptions.php | 5 + .../worker/DoorkeeperFeedWorkerAsana.php | 10 + .../worker/DoorkeeperFeedWorkerJIRA.php | 5 + .../receiver/PhabricatorMailReceiver.php | 5 + ...bricatorPeopleProfilePictureController.php | 5 + .../storage/PhabricatorExternalAccount.php | 36 +- ...abricatorSettingsPanelExternalAccounts.php | 5 + .../PhabricatorSettingsPanelSessions.php | 5 + 15 files changed, 281 insertions(+), 174 deletions(-) diff --git a/resources/celerity/map.php b/resources/celerity/map.php index b57104b888..2f2f83307f 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -8,7 +8,7 @@ return array( 'names' => array( 'core.pkg.css' => 'c2c68e64', - 'core.pkg.js' => 'f8ec7ddc', + 'core.pkg.js' => '2b9e8efd', 'darkconsole.pkg.js' => 'df001cab', 'differential.pkg.css' => '4a93db37', 'differential.pkg.js' => '7528cfc9', @@ -163,18 +163,18 @@ return array( 'rsrc/externals/font/fontawesome/fontawesome-webfont.woff' => 'a119ee5e', 'rsrc/externals/font/sourcesans/SourceSansPro.woff' => '3614608c', 'rsrc/externals/font/sourcesans/SourceSansProBold.woff' => 'cbf46566', - 'rsrc/externals/javelin/core/Event.js' => '69815cac', - 'rsrc/externals/javelin/core/Stratcom.js' => 'c293f7b9', + 'rsrc/externals/javelin/core/Event.js' => '85ea0626', + 'rsrc/externals/javelin/core/Stratcom.js' => '8b0ad945', 'rsrc/externals/javelin/core/__tests__/event-stop-and-kill.js' => '717554e4', 'rsrc/externals/javelin/core/__tests__/install.js' => 'c432ee85', 'rsrc/externals/javelin/core/__tests__/stratcom.js' => 'da194d4b', 'rsrc/externals/javelin/core/__tests__/util.js' => 'd3b157a9', 'rsrc/externals/javelin/core/init.js' => 'b88ab49e', 'rsrc/externals/javelin/core/init_node.js' => 'd7dde471', - 'rsrc/externals/javelin/core/install.js' => '52a92793', - 'rsrc/externals/javelin/core/util.js' => '65b0b249', - 'rsrc/externals/javelin/docs/Base.js' => '897bb199', - 'rsrc/externals/javelin/docs/onload.js' => '81fb4862', + 'rsrc/externals/javelin/core/install.js' => '1ffb3a9c', + 'rsrc/externals/javelin/core/util.js' => 'a23de73d', + 'rsrc/externals/javelin/docs/Base.js' => '74676256', + 'rsrc/externals/javelin/docs/onload.js' => 'e819c479', 'rsrc/externals/javelin/ext/fx/Color.js' => '7e41274a', 'rsrc/externals/javelin/ext/fx/FX.js' => '54b612ba', 'rsrc/externals/javelin/ext/reactor/core/DynVal.js' => 'f6555212', @@ -193,31 +193,31 @@ return array( 'rsrc/externals/javelin/ext/view/__tests__/ViewInterpreter.js' => '7a94d6a5', 'rsrc/externals/javelin/ext/view/__tests__/ViewRenderer.js' => '5426001c', 'rsrc/externals/javelin/lib/Cookie.js' => '6b3dcf44', - 'rsrc/externals/javelin/lib/DOM.js' => '07d99a3d', + 'rsrc/externals/javelin/lib/DOM.js' => 'c4569c05', 'rsrc/externals/javelin/lib/History.js' => 'c60f4327', - 'rsrc/externals/javelin/lib/JSON.js' => '08e56a4e', - 'rsrc/externals/javelin/lib/Mask.js' => 'b9f26029', - 'rsrc/externals/javelin/lib/Request.js' => '7bad574b', + 'rsrc/externals/javelin/lib/JSON.js' => '69adf288', + 'rsrc/externals/javelin/lib/Mask.js' => '8a41885b', + 'rsrc/externals/javelin/lib/Request.js' => '97258e55', 'rsrc/externals/javelin/lib/Resource.js' => '0f81f8df', 'rsrc/externals/javelin/lib/Routable.js' => 'b3e7d692', 'rsrc/externals/javelin/lib/Router.js' => '29274e2b', - 'rsrc/externals/javelin/lib/URI.js' => 'd9a9b862', - 'rsrc/externals/javelin/lib/Vector.js' => 'bd0aedcd', - 'rsrc/externals/javelin/lib/Workflow.js' => '09b15cf1', + 'rsrc/externals/javelin/lib/URI.js' => '6eff08aa', + 'rsrc/externals/javelin/lib/Vector.js' => '23cbb8ac', + 'rsrc/externals/javelin/lib/Workflow.js' => 'd149e002', 'rsrc/externals/javelin/lib/__tests__/Cookie.js' => '5ed109e8', 'rsrc/externals/javelin/lib/__tests__/DOM.js' => 'c984504b', 'rsrc/externals/javelin/lib/__tests__/JSON.js' => '2295d074', 'rsrc/externals/javelin/lib/__tests__/URI.js' => '003ed329', 'rsrc/externals/javelin/lib/__tests__/behavior.js' => '1ea62783', - 'rsrc/externals/javelin/lib/behavior.js' => '8a3ed18b', - 'rsrc/externals/javelin/lib/control/tokenizer/Tokenizer.js' => 'e7c21fb3', - 'rsrc/externals/javelin/lib/control/typeahead/Typeahead.js' => 'c54eeefb', - 'rsrc/externals/javelin/lib/control/typeahead/normalizer/TypeaheadNormalizer.js' => '5f850b5c', - 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadCompositeSource.js' => '84f34ab1', - 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadOnDemandSource.js' => 'a79b75a4', - 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadPreloadedSource.js' => '66815d9c', - 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadSource.js' => '62e18640', - 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadStaticSource.js' => 'cdde23f1', + 'rsrc/externals/javelin/lib/behavior.js' => '61cbc29a', + 'rsrc/externals/javelin/lib/control/tokenizer/Tokenizer.js' => 'a5b67173', + 'rsrc/externals/javelin/lib/control/typeahead/Typeahead.js' => '61f72a3d', + 'rsrc/externals/javelin/lib/control/typeahead/normalizer/TypeaheadNormalizer.js' => 'aa93c7b0', + 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadCompositeSource.js' => '503e17fd', + 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadOnDemandSource.js' => '8b3fd187', + 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadPreloadedSource.js' => '54f314a0', + 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadSource.js' => '210aa43b', + 'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadStaticSource.js' => '316b8fa1', 'rsrc/externals/raphael/g.raphael.js' => '40dde778', 'rsrc/externals/raphael/g.raphael.line.js' => '40da039e', 'rsrc/externals/raphael/raphael.js' => '51ee6b43', @@ -415,7 +415,7 @@ return array( 'rsrc/js/application/projects/behavior-project-create.js' => '065227cc', 'rsrc/js/application/releeph/releeph-preview-branch.js' => 'b2b4fbaf', 'rsrc/js/application/releeph/releeph-request-state-change.js' => 'ab836011', - 'rsrc/js/application/releeph/releeph-request-typeahead.js' => 'cd9e7094', + 'rsrc/js/application/releeph/releeph-request-typeahead.js' => 'de2e896f', 'rsrc/js/application/repository/repository-crossreference.js' => 'f9539603', 'rsrc/js/application/search/behavior-reorder-queries.js' => 'e9581f08', 'rsrc/js/application/slowvote/behavior-slowvote-embed.js' => 'd6f54db0', @@ -480,7 +480,7 @@ return array( 'rsrc/js/core/behavior-reveal-content.js' => '60821bc7', 'rsrc/js/core/behavior-search-typeahead.js' => '5a376f34', 'rsrc/js/core/behavior-select-on-click.js' => '4e3e79a6', - 'rsrc/js/core/behavior-toggle-class.js' => 'a82a7769', + 'rsrc/js/core/behavior-toggle-class.js' => 'e566f52c', 'rsrc/js/core/behavior-tokenizer.js' => 'b3a4b884', 'rsrc/js/core/behavior-tooltip.js' => '3ee3408b', 'rsrc/js/core/behavior-watch-anchor.js' => '06e05112', @@ -541,7 +541,7 @@ return array( 'herald-test-css' => '778b008e', 'inline-comment-summary-css' => '8cfd34e8', 'javelin-aphlict' => '4a07e8e3', - 'javelin-behavior' => '8a3ed18b', + 'javelin-behavior' => '61cbc29a', 'javelin-behavior-aphlict-dropdown' => 'f51afce0', 'javelin-behavior-aphlict-listen' => 'a826c925', 'javelin-behavior-aphlict-status' => '58f7803f', @@ -642,7 +642,7 @@ return array( 'javelin-behavior-refresh-csrf' => '7814b593', 'javelin-behavior-releeph-preview-branch' => 'b2b4fbaf', 'javelin-behavior-releeph-request-state-change' => 'ab836011', - 'javelin-behavior-releeph-request-typeahead' => 'cd9e7094', + 'javelin-behavior-releeph-request-typeahead' => 'de2e896f', 'javelin-behavior-remarkup-preview' => 'f7379f45', 'javelin-behavior-reorder-applications' => '76b9fc3e', 'javelin-behavior-repository-crossreference' => 'f9539603', @@ -651,47 +651,47 @@ return array( 'javelin-behavior-slowvote-embed' => 'd6f54db0', 'javelin-behavior-stripe-payment-form' => '1693a296', 'javelin-behavior-test-payment-form' => 'ab8d2723', - 'javelin-behavior-toggle-class' => 'a82a7769', + 'javelin-behavior-toggle-class' => 'e566f52c', 'javelin-behavior-view-placeholder' => '2fa810fc', 'javelin-behavior-workflow' => '0a3f3021', 'javelin-color' => '7e41274a', 'javelin-cookie' => '6b3dcf44', 'javelin-diffusion-locate-file-source' => 'b42eddc7', - 'javelin-dom' => '07d99a3d', + 'javelin-dom' => 'c4569c05', 'javelin-dynval' => 'f6555212', - 'javelin-event' => '69815cac', + 'javelin-event' => '85ea0626', 'javelin-fx' => '54b612ba', 'javelin-history' => 'c60f4327', - 'javelin-install' => '52a92793', - 'javelin-json' => '08e56a4e', + 'javelin-install' => '1ffb3a9c', + 'javelin-json' => '69adf288', 'javelin-magical-init' => 'b88ab49e', - 'javelin-mask' => 'b9f26029', + 'javelin-mask' => '8a41885b', 'javelin-reactor' => '77b1cf6f', 'javelin-reactor-dom' => 'b6d401d6', 'javelin-reactor-node-calmer' => '76f4ebed', 'javelin-reactornode' => 'b4c30592', - 'javelin-request' => '7bad574b', + 'javelin-request' => '97258e55', 'javelin-resource' => '0f81f8df', 'javelin-routable' => 'b3e7d692', 'javelin-router' => '29274e2b', - 'javelin-stratcom' => 'c293f7b9', - 'javelin-tokenizer' => 'e7c21fb3', - 'javelin-typeahead' => 'c54eeefb', - 'javelin-typeahead-composite-source' => '84f34ab1', - 'javelin-typeahead-normalizer' => '5f850b5c', - 'javelin-typeahead-ondemand-source' => 'a79b75a4', - 'javelin-typeahead-preloaded-source' => '66815d9c', - 'javelin-typeahead-source' => '62e18640', - 'javelin-typeahead-static-source' => 'cdde23f1', - 'javelin-uri' => 'd9a9b862', - 'javelin-util' => '65b0b249', - 'javelin-vector' => 'bd0aedcd', + 'javelin-stratcom' => '8b0ad945', + 'javelin-tokenizer' => 'a5b67173', + 'javelin-typeahead' => '61f72a3d', + 'javelin-typeahead-composite-source' => '503e17fd', + 'javelin-typeahead-normalizer' => 'aa93c7b0', + 'javelin-typeahead-ondemand-source' => '8b3fd187', + 'javelin-typeahead-preloaded-source' => '54f314a0', + 'javelin-typeahead-source' => '210aa43b', + 'javelin-typeahead-static-source' => '316b8fa1', + 'javelin-uri' => '6eff08aa', + 'javelin-util' => 'a23de73d', + 'javelin-vector' => '23cbb8ac', 'javelin-view' => '0f764c35', 'javelin-view-html' => 'e5b406f9', 'javelin-view-interpreter' => '0c33c1a0', 'javelin-view-renderer' => '6c2b09a2', 'javelin-view-visitor' => 'efe49472', - 'javelin-workflow' => '09b15cf1', + 'javelin-workflow' => 'd149e002', 'lightbox-attachment-css' => '7acac05d', 'maniphest-batch-editor' => '8f380ebc', 'maniphest-report-css' => '6fc16517', @@ -872,30 +872,6 @@ return array( 4 => 'javelin-util', 5 => 'phabricator-busy', ), - '07d99a3d' => - array( - 0 => 'javelin-magical-init', - 1 => 'javelin-install', - 2 => 'javelin-util', - 3 => 'javelin-vector', - 4 => 'javelin-stratcom', - ), - '08e56a4e' => - array( - 0 => 'javelin-install', - ), - '09b15cf1' => - array( - 0 => 'javelin-stratcom', - 1 => 'javelin-request', - 2 => 'javelin-dom', - 3 => 'javelin-vector', - 4 => 'javelin-install', - 5 => 'javelin-util', - 6 => 'javelin-mask', - 7 => 'javelin-uri', - 8 => 'javelin-routable', - ), '0a3f3021' => array( 0 => 'javelin-behavior', @@ -1015,6 +991,18 @@ return array( 1 => 'javelin-dom', 2 => 'javelin-reactor-dom', ), + '1ffb3a9c' => + array( + 0 => 'javelin-util', + 1 => 'javelin-magical-init', + ), + '210aa43b' => + array( + 0 => 'javelin-install', + 1 => 'javelin-util', + 2 => 'javelin-dom', + 3 => 'javelin-typeahead-normalizer', + ), '2290aeef' => array( 0 => 'javelin-install', @@ -1029,6 +1017,11 @@ return array( 1 => 'javelin-dom', 2 => 'javelin-vector', ), + '23cbb8ac' => + array( + 0 => 'javelin-install', + 1 => 'javelin-event', + ), '2926fff2' => array( 0 => 'javelin-behavior', @@ -1063,6 +1056,11 @@ return array( 2 => 'javelin-view-renderer', 3 => 'javelin-install', ), + '316b8fa1' => + array( + 0 => 'javelin-install', + 1 => 'javelin-typeahead-source', + ), '357b6e9b' => array( 0 => 'javelin-behavior', @@ -1225,23 +1223,31 @@ return array( 1 => 'javelin-stratcom', 2 => 'javelin-dom', ), + '503e17fd' => + array( + 0 => 'javelin-install', + 1 => 'javelin-typeahead-source', + 2 => 'javelin-util', + ), '519705ea' => array( 0 => 'javelin-install', 1 => 'javelin-dom', 2 => 'javelin-reactor-dom', ), - '52a92793' => - array( - 0 => 'javelin-util', - 1 => 'javelin-magical-init', - ), '54b612ba' => array( 0 => 'javelin-color', 1 => 'javelin-install', 2 => 'javelin-util', ), + '54f314a0' => + array( + 0 => 'javelin-install', + 1 => 'javelin-util', + 2 => 'javelin-request', + 3 => 'javelin-typeahead-source', + ), '558829c2' => array( 0 => 'javelin-stratcom', @@ -1288,10 +1294,6 @@ return array( 0 => 'javelin-behavior', 1 => 'javelin-stratcom', ), - '5f850b5c' => - array( - 0 => 'javelin-install', - ), '5fefb143' => array( 0 => 'javelin-behavior', @@ -1312,12 +1314,17 @@ return array( 2 => 'javelin-dom', 3 => 'javelin-workflow', ), - '62e18640' => + '61cbc29a' => + array( + 0 => 'javelin-magical-init', + 1 => 'javelin-util', + ), + '61f72a3d' => array( 0 => 'javelin-install', - 1 => 'javelin-util', - 2 => 'javelin-dom', - 3 => 'javelin-typeahead-normalizer', + 1 => 'javelin-dom', + 2 => 'javelin-vector', + 3 => 'javelin-util', ), '6453c869' => array( @@ -1325,14 +1332,7 @@ return array( 1 => 'javelin-dom', 2 => 'javelin-fx', ), - '66815d9c' => - array( - 0 => 'javelin-install', - 1 => 'javelin-util', - 2 => 'javelin-request', - 3 => 'javelin-typeahead-source', - ), - '69815cac' => + '69adf288' => array( 0 => 'javelin-install', ), @@ -1360,6 +1360,12 @@ return array( 1 => 'javelin-dom', 2 => 'javelin-util', ), + '6eff08aa' => + array( + 0 => 'javelin-install', + 1 => 'javelin-util', + 2 => 'javelin-stratcom', + ), '710f209e' => array( 0 => 'javelin-behavior', @@ -1433,17 +1439,6 @@ return array( 2 => 'javelin-stratcom', 3 => 'javelin-util', ), - '7bad574b' => - array( - 0 => 'javelin-install', - 1 => 'javelin-stratcom', - 2 => 'javelin-util', - 3 => 'javelin-behavior', - 4 => 'javelin-json', - 5 => 'javelin-dom', - 6 => 'javelin-resource', - 7 => 'javelin-routable', - ), '7c273581' => array( 0 => 'javelin-behavior', @@ -1491,12 +1486,6 @@ return array( 3 => 'javelin-workflow', 4 => 'phabricator-draggable-list', ), - '84f34ab1' => - array( - 0 => 'javelin-install', - 1 => 'javelin-typeahead-source', - 2 => 'javelin-util', - ), '85ab3c8e' => array( 0 => 'javelin-behavior', @@ -1505,6 +1494,10 @@ return array( 3 => 'javelin-workflow', 4 => 'javelin-stratcom', ), + '85ea0626' => + array( + 0 => 'javelin-install', + ), '880fa5ac' => array( 0 => 'javelin-behavior', @@ -1524,10 +1517,24 @@ return array( 3 => 'javelin-view-interpreter', 4 => 'javelin-view-renderer', ), - '8a3ed18b' => + '8a41885b' => array( - 0 => 'javelin-magical-init', + 0 => 'javelin-install', + 1 => 'javelin-dom', + ), + '8b0ad945' => + array( + 0 => 'javelin-install', + 1 => 'javelin-event', + 2 => 'javelin-util', + 3 => 'javelin-magical-init', + ), + '8b3fd187' => + array( + 0 => 'javelin-install', 1 => 'javelin-util', + 2 => 'javelin-request', + 3 => 'javelin-typeahead-source', ), '8d199d97' => array( @@ -1575,6 +1582,17 @@ return array( 3 => 'javelin-workflow', 4 => 'javelin-util', ), + '97258e55' => + array( + 0 => 'javelin-install', + 1 => 'javelin-stratcom', + 2 => 'javelin-util', + 3 => 'javelin-behavior', + 4 => 'javelin-json', + 5 => 'javelin-dom', + 6 => 'javelin-resource', + 7 => 'javelin-routable', + ), '988040b4' => array( 0 => 'javelin-install', @@ -1631,17 +1649,17 @@ return array( 3 => 'javelin-stratcom', 4 => 'javelin-vector', ), + 'a5b67173' => + array( + 0 => 'javelin-dom', + 1 => 'javelin-util', + 2 => 'javelin-stratcom', + 3 => 'javelin-install', + ), 'a5d7cf86' => array( 0 => 'javelin-dom', ), - 'a79b75a4' => - array( - 0 => 'javelin-install', - 1 => 'javelin-util', - 2 => 'javelin-request', - 3 => 'javelin-typeahead-source', - ), 'a80d0378' => array( 0 => 'javelin-behavior', @@ -1661,12 +1679,6 @@ return array( 8 => 'javelin-util', 9 => 'phabricator-notification', ), - 'a82a7769' => - array( - 0 => 'javelin-behavior', - 1 => 'javelin-stratcom', - 2 => 'javelin-dom', - ), 'a8d8459d' => array( 0 => 'javelin-behavior', @@ -1697,6 +1709,10 @@ return array( 4 => 'javelin-util', 5 => 'phabricator-prefab', ), + 'aa93c7b0' => + array( + 0 => 'javelin-install', + ), 'ab836011' => array( 0 => 'javelin-behavior', @@ -1782,22 +1798,12 @@ return array( 3 => 'javelin-dom', 4 => 'phabricator-draggable-list', ), - 'b9f26029' => - array( - 0 => 'javelin-install', - 1 => 'javelin-dom', - ), 'bba9eedf' => array( 0 => 'javelin-behavior', 1 => 'javelin-stratcom', 2 => 'javelin-dom', ), - 'bd0aedcd' => - array( - 0 => 'javelin-install', - 1 => 'javelin-event', - ), 'bd4c8dca' => array( 0 => 'javelin-install', @@ -1828,19 +1834,13 @@ return array( 2 => 'javelin-util', 3 => 'phabricator-shaped-request', ), - 'c293f7b9' => + 'c4569c05' => array( - 0 => 'javelin-install', - 1 => 'javelin-event', + 0 => 'javelin-magical-init', + 1 => 'javelin-install', 2 => 'javelin-util', - 3 => 'javelin-magical-init', - ), - 'c54eeefb' => - array( - 0 => 'javelin-install', - 1 => 'javelin-dom', - 2 => 'javelin-vector', - 3 => 'javelin-util', + 3 => 'javelin-vector', + 4 => 'javelin-stratcom', ), 'c60f4327' => array( @@ -1856,18 +1856,17 @@ return array( 2 => 'javelin-stratcom', 3 => 'phabricator-phtize', ), - 'cd9e7094' => + 'd149e002' => array( - 0 => 'javelin-behavior', - 1 => 'javelin-dom', - 2 => 'javelin-typeahead', - 3 => 'javelin-typeahead-ondemand-source', - 4 => 'javelin-dom', - ), - 'cdde23f1' => - array( - 0 => 'javelin-install', - 1 => 'javelin-typeahead-source', + 0 => 'javelin-stratcom', + 1 => 'javelin-request', + 2 => 'javelin-dom', + 3 => 'javelin-vector', + 4 => 'javelin-install', + 5 => 'javelin-util', + 6 => 'javelin-mask', + 7 => 'javelin-uri', + 8 => 'javelin-routable', ), 'd19198c8' => array( @@ -1926,12 +1925,6 @@ return array( 2 => 'javelin-util', 3 => 'phabricator-shaped-request', ), - 'd9a9b862' => - array( - 0 => 'javelin-install', - 1 => 'javelin-util', - 2 => 'javelin-stratcom', - ), 'dd7e8ef5' => array( 0 => 'javelin-behavior', @@ -1940,6 +1933,14 @@ return array( 3 => 'javelin-util', 4 => 'javelin-stratcom', ), + 'de2e896f' => + array( + 0 => 'javelin-behavior', + 1 => 'javelin-dom', + 2 => 'javelin-typeahead', + 3 => 'javelin-typeahead-ondemand-source', + 4 => 'javelin-dom', + ), 'e10f8e18' => array( 0 => 'javelin-behavior', @@ -1970,6 +1971,12 @@ return array( 3 => 'javelin-dom', 4 => 'javelin-uri', ), + 'e566f52c' => + array( + 0 => 'javelin-behavior', + 1 => 'javelin-stratcom', + 2 => 'javelin-dom', + ), 'e5822781' => array( 0 => 'javelin-behavior', @@ -1985,13 +1992,6 @@ return array( 2 => 'javelin-view-visitor', 3 => 'javelin-util', ), - 'e7c21fb3' => - array( - 0 => 'javelin-dom', - 1 => 'javelin-util', - 2 => 'javelin-stratcom', - 3 => 'javelin-install', - ), 'e9581f08' => array( 0 => 'javelin-behavior', diff --git a/src/applications/auth/controller/PhabricatorAuthController.php b/src/applications/auth/controller/PhabricatorAuthController.php index 99359970f0..91030d5749 100644 --- a/src/applications/auth/controller/PhabricatorAuthController.php +++ b/src/applications/auth/controller/PhabricatorAuthController.php @@ -143,12 +143,19 @@ abstract class PhabricatorAuthController extends PhabricatorController { // be logged in yet, and because we want to tailor an error message to // distinguish between "not usable" and "does not exist". We do explicit // checks later on to make sure this account is valid for the intended - // operation. + // operation. This requires edit permission for completeness and consistency + // but it won't actually be meaningfully checked because we're using the + // ominpotent user. $account = id(new PhabricatorExternalAccountQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withAccountSecrets(array($account_key)) ->needImages(true) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) ->executeOne(); if (!$account) { diff --git a/src/applications/auth/management/PhabricatorAuthManagementRefreshWorkflow.php b/src/applications/auth/management/PhabricatorAuthManagementRefreshWorkflow.php index fa7bb85360..27382eb48b 100644 --- a/src/applications/auth/management/PhabricatorAuthManagementRefreshWorkflow.php +++ b/src/applications/auth/management/PhabricatorAuthManagementRefreshWorkflow.php @@ -36,7 +36,12 @@ final class PhabricatorAuthManagementRefreshWorkflow $viewer = $this->getViewer(); $query = id(new PhabricatorExternalAccountQuery()) - ->setViewer($viewer); + ->setViewer($viewer) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )); $username = $args->getArg('user'); if (strlen($username)) { diff --git a/src/applications/auth/query/PhabricatorExternalAccountQuery.php b/src/applications/auth/query/PhabricatorExternalAccountQuery.php index 0198d5bd38..36f63f78a5 100644 --- a/src/applications/auth/query/PhabricatorExternalAccountQuery.php +++ b/src/applications/auth/query/PhabricatorExternalAccountQuery.php @@ -1,5 +1,15 @@ withUserPHIDs(array($viewer->getPHID())) ->withAccountTypes(array('github')) ->withAccountDomains(array($repo_domain)) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) ->executeOne(); if (!$this->account) { diff --git a/src/applications/doorkeeper/bridge/DoorkeeperBridgeAsana.php b/src/applications/doorkeeper/bridge/DoorkeeperBridgeAsana.php index 855498f471..19191eb03c 100644 --- a/src/applications/doorkeeper/bridge/DoorkeeperBridgeAsana.php +++ b/src/applications/doorkeeper/bridge/DoorkeeperBridgeAsana.php @@ -37,6 +37,11 @@ final class DoorkeeperBridgeAsana extends DoorkeeperBridge { ->withUserPHIDs(array($viewer->getPHID())) ->withAccountTypes(array($provider->getProviderType())) ->withAccountDomains(array($provider->getProviderDomain())) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) ->execute(); if (!$accounts) { diff --git a/src/applications/doorkeeper/bridge/DoorkeeperBridgeJIRA.php b/src/applications/doorkeeper/bridge/DoorkeeperBridgeJIRA.php index 3cc8393f7e..9698237f1d 100644 --- a/src/applications/doorkeeper/bridge/DoorkeeperBridgeJIRA.php +++ b/src/applications/doorkeeper/bridge/DoorkeeperBridgeJIRA.php @@ -31,6 +31,11 @@ final class DoorkeeperBridgeJIRA extends DoorkeeperBridge { ->setViewer($viewer) ->withUserPHIDs(array($viewer->getPHID())) ->withAccountTypes(array($provider->getProviderType())) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) ->execute(); if (!$accounts) { diff --git a/src/applications/doorkeeper/option/PhabricatorAsanaConfigOptions.php b/src/applications/doorkeeper/option/PhabricatorAsanaConfigOptions.php index 33b32dc28f..ca452a5ff8 100644 --- a/src/applications/doorkeeper/option/PhabricatorAsanaConfigOptions.php +++ b/src/applications/doorkeeper/option/PhabricatorAsanaConfigOptions.php @@ -59,6 +59,11 @@ final class PhabricatorAsanaConfigOptions ->withUserPHIDs(array($viewer->getPHID())) ->withAccountTypes(array($provider->getProviderType())) ->withAccountDomains(array($provider->getProviderDomain())) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) ->executeOne(); if (!$account) { return null; diff --git a/src/applications/doorkeeper/worker/DoorkeeperFeedWorkerAsana.php b/src/applications/doorkeeper/worker/DoorkeeperFeedWorkerAsana.php index 50a2dfabf2..4cb18ea80d 100644 --- a/src/applications/doorkeeper/worker/DoorkeeperFeedWorkerAsana.php +++ b/src/applications/doorkeeper/worker/DoorkeeperFeedWorkerAsana.php @@ -524,6 +524,11 @@ final class DoorkeeperFeedWorkerAsana extends DoorkeeperFeedWorker { ->withUserPHIDs($all_phids) ->withAccountTypes(array($provider->getProviderType())) ->withAccountDomains(array($provider->getProviderDomain())) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) ->execute(); foreach ($accounts as $account) { @@ -549,6 +554,11 @@ final class DoorkeeperFeedWorkerAsana extends DoorkeeperFeedWorker { ->withUserPHIDs($user_phids) ->withAccountTypes(array($provider->getProviderType())) ->withAccountDomains(array($provider->getProviderDomain())) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) ->execute(); // Reorder accounts in the original order. diff --git a/src/applications/doorkeeper/worker/DoorkeeperFeedWorkerJIRA.php b/src/applications/doorkeeper/worker/DoorkeeperFeedWorkerJIRA.php index d6686b7de7..c7ba08dd70 100644 --- a/src/applications/doorkeeper/worker/DoorkeeperFeedWorkerJIRA.php +++ b/src/applications/doorkeeper/worker/DoorkeeperFeedWorkerJIRA.php @@ -63,6 +63,11 @@ final class DoorkeeperFeedWorkerJIRA extends DoorkeeperFeedWorker { ->withUserPHIDs($try_users) ->withAccountTypes(array($provider->getProviderType())) ->withAccountDomains(array($domain)) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) ->execute(); // Reorder accounts in the original order. // TODO: This needs to be adjusted if/when we allow you to link multiple diff --git a/src/applications/metamta/receiver/PhabricatorMailReceiver.php b/src/applications/metamta/receiver/PhabricatorMailReceiver.php index fd0f0e1bb1..1fd6068468 100644 --- a/src/applications/metamta/receiver/PhabricatorMailReceiver.php +++ b/src/applications/metamta/receiver/PhabricatorMailReceiver.php @@ -107,6 +107,11 @@ abstract class PhabricatorMailReceiver { ->withAccountTypes(array('email')) ->withAccountDomains(array($from_obj->getDomainName(), 'self')) ->withAccountIDs(array($from_obj->getAddress())) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) ->loadOneOrCreate(); return $xuser->getPhabricatorUser(); } else { diff --git a/src/applications/people/controller/PhabricatorPeopleProfilePictureController.php b/src/applications/people/controller/PhabricatorPeopleProfilePictureController.php index 82426c51b4..afee9ea84f 100644 --- a/src/applications/people/controller/PhabricatorPeopleProfilePictureController.php +++ b/src/applications/people/controller/PhabricatorPeopleProfilePictureController.php @@ -125,6 +125,11 @@ final class PhabricatorPeopleProfilePictureController ->setViewer($viewer) ->withUserPHIDs(array($user->getPHID())) ->needImages(true) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) ->execute(); foreach ($accounts as $account) { diff --git a/src/applications/people/storage/PhabricatorExternalAccount.php b/src/applications/people/storage/PhabricatorExternalAccount.php index 94ca59fb02..92a22d0c7d 100644 --- a/src/applications/people/storage/PhabricatorExternalAccount.php +++ b/src/applications/people/storage/PhabricatorExternalAccount.php @@ -84,6 +84,25 @@ final class PhabricatorExternalAccount extends PhabricatorUserDAO return true; } + public function getDisplayName() { + if (strlen($this->displayName)) { + return $this->displayName; + } + + // TODO: Figure out how much identifying information we're going to show + // to users about external accounts. For now, just show a string which is + // clearly not an error, but don't disclose any identifying information. + + $map = array( + 'email' => pht('Email User'), + ); + + $type = $this->getAccountType(); + + return idx($map, $type, pht('"%s" User', $type)); + } + + /* -( PhabricatorPolicyInterface )----------------------------------------- */ @@ -91,11 +110,17 @@ final class PhabricatorExternalAccount extends PhabricatorUserDAO public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { - return PhabricatorPolicies::POLICY_NOONE; + switch ($capability) { + case PhabricatorPolicyCapability::CAN_VIEW: + return PhabricatorPolicies::getMostOpenPolicy(); + case PhabricatorPolicyCapability::CAN_EDIT: + return PhabricatorPolicies::POLICY_NOONE; + } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { @@ -103,8 +128,13 @@ final class PhabricatorExternalAccount extends PhabricatorUserDAO } public function describeAutomaticCapability($capability) { - // TODO: (T603) This is complicated. - return null; + switch ($capability) { + case PhabricatorPolicyCapability::CAN_VIEW: + return null; + case PhabricatorPolicyCapability::CAN_EDIT: + return pht( + 'External accounts can only be edited by the account owner.'); + } } } diff --git a/src/applications/settings/panel/PhabricatorSettingsPanelExternalAccounts.php b/src/applications/settings/panel/PhabricatorSettingsPanelExternalAccounts.php index 5faaf5672d..929ce9c3f3 100644 --- a/src/applications/settings/panel/PhabricatorSettingsPanelExternalAccounts.php +++ b/src/applications/settings/panel/PhabricatorSettingsPanelExternalAccounts.php @@ -28,6 +28,11 @@ final class PhabricatorSettingsPanelExternalAccounts ->setViewer($viewer) ->withUserPHIDs(array($viewer->getPHID())) ->needImages(true) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) ->execute(); $linked_head = id(new PHUIHeaderView()) diff --git a/src/applications/settings/panel/PhabricatorSettingsPanelSessions.php b/src/applications/settings/panel/PhabricatorSettingsPanelSessions.php index abbd38be25..4103f6c9ab 100644 --- a/src/applications/settings/panel/PhabricatorSettingsPanelSessions.php +++ b/src/applications/settings/panel/PhabricatorSettingsPanelSessions.php @@ -25,6 +25,11 @@ final class PhabricatorSettingsPanelSessions $accounts = id(new PhabricatorExternalAccountQuery()) ->setViewer($viewer) ->withUserPHIDs(array($viewer->getPHID())) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) ->execute(); $identity_phids = mpull($accounts, 'getPHID');