Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F89291
D7751.id17532.diff
All Users
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
30 KB
Referenced Files
None
Subscribers
None
D7751.id17532.diff
View Options
diff --git a/resources/sql/patches/20131210.filenonce.sql b/resources/sql/patches/20131210.filenonce.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/patches/20131210.filenonce.sql
@@ -0,0 +1,9 @@
+CREATE TABLE {$NAMESPACE}_file.file_nonce (
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ filePHID VARCHAR(64) NOT NULL COLLATE utf8_bin,
+ nonce VARCHAR(32) NOT NULL COLLATE utf8_bin,
+ dateExpiry INT UNSIGNED NOT NULL,
+ dateCreated INT UNSIGNED NOT NULL,
+ dateModified INT UNSIGNED NOT NULL,
+ UNIQUE KEY `key_nonce` (filePHID, nonce)
+) ENGINE=InnoDB, COLLATE utf8_general_ci;
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1413,6 +1413,7 @@
'PhabricatorFileLinkListView' => 'view/layout/PhabricatorFileLinkListView.php',
'PhabricatorFileLinkView' => 'view/layout/PhabricatorFileLinkView.php',
'PhabricatorFileListController' => 'applications/files/controller/PhabricatorFileListController.php',
+ 'PhabricatorFileNonce' => 'applications/files/storage/PhabricatorFileNonce.php',
'PhabricatorFilePHIDTypeFile' => 'applications/files/phid/PhabricatorFilePHIDTypeFile.php',
'PhabricatorFileQuery' => 'applications/files/query/PhabricatorFileQuery.php',
'PhabricatorFileSearchEngine' => 'applications/files/query/PhabricatorFileSearchEngine.php',
@@ -2176,6 +2177,7 @@
'PhortuneTestPaymentProvider' => 'applications/phortune/provider/PhortuneTestPaymentProvider.php',
'PhortuneWePayPaymentProvider' => 'applications/phortune/provider/PhortuneWePayPaymentProvider.php',
'PhragmentBrowseController' => 'applications/phragment/controller/PhragmentBrowseController.php',
+ 'PhragmentCapabilityCanCreate' => 'applications/phragment/capability/PhragmentCapabilityCanCreate.php',
'PhragmentController' => 'applications/phragment/controller/PhragmentController.php',
'PhragmentCreateController' => 'applications/phragment/controller/PhragmentCreateController.php',
'PhragmentDAO' => 'applications/phragment/storage/PhragmentDAO.php',
@@ -2189,6 +2191,7 @@
'PhragmentPHIDTypeSnapshot' => 'applications/phragment/phid/PhragmentPHIDTypeSnapshot.php',
'PhragmentPatchController' => 'applications/phragment/controller/PhragmentPatchController.php',
'PhragmentPatchUtil' => 'applications/phragment/util/PhragmentPatchUtil.php',
+ 'PhragmentPolicyController' => 'applications/phragment/controller/PhragmentPolicyController.php',
'PhragmentRevertController' => 'applications/phragment/controller/PhragmentRevertController.php',
'PhragmentSnapshot' => 'applications/phragment/storage/PhragmentSnapshot.php',
'PhragmentSnapshotChild' => 'applications/phragment/storage/PhragmentSnapshotChild.php',
@@ -3932,6 +3935,7 @@
0 => 'PhabricatorFileController',
1 => 'PhabricatorApplicationSearchResultsControllerInterface',
),
+ 'PhabricatorFileNonce' => 'PhabricatorFileDAO',
'PhabricatorFilePHIDTypeFile' => 'PhabricatorPHIDType',
'PhabricatorFileQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorFileSearchEngine' => 'PhabricatorApplicationSearchEngine',
@@ -4782,6 +4786,7 @@
'PhortuneTestPaymentProvider' => 'PhortunePaymentProvider',
'PhortuneWePayPaymentProvider' => 'PhortunePaymentProvider',
'PhragmentBrowseController' => 'PhragmentController',
+ 'PhragmentCapabilityCanCreate' => 'PhabricatorPolicyCapability',
'PhragmentController' => 'PhabricatorController',
'PhragmentCreateController' => 'PhragmentController',
'PhragmentDAO' => 'PhabricatorLiskDAO',
@@ -4803,6 +4808,7 @@
'PhragmentPHIDTypeSnapshot' => 'PhabricatorPHIDType',
'PhragmentPatchController' => 'PhragmentController',
'PhragmentPatchUtil' => 'Phobject',
+ 'PhragmentPolicyController' => 'PhragmentController',
'PhragmentRevertController' => 'PhragmentController',
'PhragmentSnapshot' =>
array(
diff --git a/src/applications/files/controller/PhabricatorFileDataController.php b/src/applications/files/controller/PhabricatorFileDataController.php
--- a/src/applications/files/controller/PhabricatorFileDataController.php
+++ b/src/applications/files/controller/PhabricatorFileDataController.php
@@ -67,13 +67,35 @@
$response->setMimeType($file->getViewableMimeType());
} else {
if (!$request->isHTTPPost()) {
+ // Check if a nonce has been provided. This is used so that
+ // Phabricator can redirect users to the direct download without
+ // going through a POST submission (e.g. when a controller does
+ // a simple redirect). These tokens have a short life time (60
+ // seconds), can only be used once, and can only be generated from
+ // within Phabricator itself.
+ $nonce_exists = false;
+ if ($request->getExists('nonce')) {
+ $token = $request->getStr('nonce');
+ $nonce = id(new PhabricatorFileNonce())->loadOneWhere(
+ 'filePHID = %s AND nonce = %s AND dateExpiry < %d',
+ $file->getPHID(),
+ $request->getStr('nonce'),
+ time());
+ if ($nonce !== null) {
+ $nonce->delete();
+ $nonce_exists = true;
+ }
+ }
+
// NOTE: Require POST to download files. We'd rather go full-bore and
// do a real CSRF check, but can't currently authenticate users on the
// file domain. This should blunt any attacks based on iframes, script
// tags, applet tags, etc., at least. Send the user to the "info" page
// if they're using some other method.
- return id(new AphrontRedirectResponse())
- ->setURI(PhabricatorEnv::getProductionURI($file->getBestURI()));
+ if (!$nonce_exists) {
+ return id(new AphrontRedirectResponse())
+ ->setURI(PhabricatorEnv::getProductionURI($file->getBestURI()));
+ }
}
$response->setMimeType($file->getMimeType());
$response->setDownload($file->getName());
diff --git a/src/applications/files/storage/PhabricatorFile.php b/src/applications/files/storage/PhabricatorFile.php
--- a/src/applications/files/storage/PhabricatorFile.php
+++ b/src/applications/files/storage/PhabricatorFile.php
@@ -512,6 +512,30 @@
return (string) $uri;
}
+ /**
+ * Provides a download URI to the file with a one-time use token to permit
+ * GET requests. This should be used when redirecting the user to download
+ * the file directly.
+ *
+ * The expiry time is set to 60 seconds, as these URIs are not expected to
+ * be long lived.
+ */
+ public function getNonceURI($expiry = 60) {
+ $token = Filesystem::readRandomCharacters(32);
+
+ $nonce = id(new PhabricatorFileNonce());
+ $nonce->setFilePHID($this->getPHID());
+ $nonce->setNonce($token);
+ $nonce->setDateExpiry(time() + $expiry);
+ $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
+ $nonce->save();
+ unset($unguarded);
+
+ $uri = id(new PhutilURI($this->getViewURI()))
+ ->setQueryParam('nonce', $token);
+ return (string) $uri;
+ }
+
public function getProfileThumbURI() {
$path = '/file/xform/thumb-profile/'.$this->getPHID().'/'
.$this->getSecretKey().'/';
@@ -877,8 +901,12 @@
}
public function getPolicy($capability) {
- // TODO: Implement proper per-object policies.
- return PhabricatorPolicies::POLICY_USER;
+ switch ($capability) {
+ case PhabricatorPolicyCapability::CAN_VIEW:
+ return $this->getViewPolicy();
+ default:
+ return PhabricatorPolicies::POLICY_USER;
+ }
}
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
diff --git a/src/applications/files/storage/PhabricatorFileNonce.php b/src/applications/files/storage/PhabricatorFileNonce.php
new file mode 100644
--- /dev/null
+++ b/src/applications/files/storage/PhabricatorFileNonce.php
@@ -0,0 +1,19 @@
+<?php
+
+final class PhabricatorFileNonce extends PhabricatorFileDAO {
+
+ protected $filePHID;
+ protected $nonce;
+ protected $dateExpiry;
+
+ private $file = self::ATTACHABLE;
+
+ public function getFile() {
+ return $this->assertAttached($this->file);
+ }
+
+ public function attachFile(PhabricatorFile $file) {
+ return $this->file = $file;
+ }
+
+}
diff --git a/src/applications/phragment/application/PhabricatorApplicationPhragment.php b/src/applications/phragment/application/PhabricatorApplicationPhragment.php
--- a/src/applications/phragment/application/PhabricatorApplicationPhragment.php
+++ b/src/applications/phragment/application/PhabricatorApplicationPhragment.php
@@ -37,6 +37,7 @@
'browse/(?P<dblob>.*)' => 'PhragmentBrowseController',
'create/(?P<dblob>.*)' => 'PhragmentCreateController',
'update/(?P<dblob>.*)' => 'PhragmentUpdateController',
+ 'policy/(?P<dblob>.*)' => 'PhragmentPolicyController',
'history/(?P<dblob>.*)' => 'PhragmentHistoryController',
'zip/(?P<dblob>.*)' => 'PhragmentZIPController',
'zip@(?P<snapshot>[^/]+)/(?P<dblob>.*)' => 'PhragmentZIPController',
@@ -56,5 +57,12 @@
);
}
+ protected function getCustomCapabilities() {
+ return array(
+ PhragmentCapabilityCanCreate::CAPABILITY => array(
+ ),
+ );
+ }
+
}
diff --git a/src/applications/phragment/capability/PhragmentCapabilityCanCreate.php b/src/applications/phragment/capability/PhragmentCapabilityCanCreate.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phragment/capability/PhragmentCapabilityCanCreate.php
@@ -0,0 +1,20 @@
+<?php
+
+final class PhragmentCapabilityCanCreate
+ extends PhabricatorPolicyCapability {
+
+ const CAPABILITY = 'phragment.create';
+
+ public function getCapabilityKey() {
+ return self::CAPABILITY;
+ }
+
+ public function getCapabilityName() {
+ return pht('Can Create Fragments');
+ }
+
+ public function describeCapabilityRejection() {
+ return pht('You do not have permission to create fragments.');
+ }
+
+}
diff --git a/src/applications/phragment/controller/PhragmentBrowseController.php b/src/applications/phragment/controller/PhragmentBrowseController.php
--- a/src/applications/phragment/controller/PhragmentBrowseController.php
+++ b/src/applications/phragment/controller/PhragmentBrowseController.php
@@ -4,6 +4,10 @@
private $dblob;
+ public function shouldAllowPublic() {
+ return true;
+ }
+
public function willProcessRequest(array $data) {
$this->dblob = idx($data, "dblob", "");
}
@@ -24,11 +28,14 @@
}
$crumbs = $this->buildApplicationCrumbsWithPath($parents);
- $crumbs->addAction(
- id(new PHUIListItemView())
- ->setName(pht('Create Fragment'))
- ->setHref($this->getApplicationURI('/create/'.$path))
- ->setIcon('create'));
+ if ($this->hasApplicationCapability(
+ PhragmentCapabilityCanCreate::CAPABILITY)) {
+ $crumbs->addAction(
+ id(new PHUIListItemView())
+ ->setName(pht('Create Fragment'))
+ ->setHref($this->getApplicationURI('/create/'.$path))
+ ->setIcon('create'));
+ }
$current_box = $this->createCurrentFragmentView($current, false);
diff --git a/src/applications/phragment/controller/PhragmentController.php b/src/applications/phragment/controller/PhragmentController.php
--- a/src/applications/phragment/controller/PhragmentController.php
+++ b/src/applications/phragment/controller/PhragmentController.php
@@ -79,20 +79,29 @@
$file = null;
$file_uri = null;
if (!$fragment->isDirectory()) {
- $file = id(new PhabricatorFileQuery())
- ->setViewer($viewer)
- ->withPHIDs(array($fragment->getLatestVersion()->getFilePHID()))
- ->executeOne();
- if ($file !== null) {
- $file_uri = $file->getBestURI();
+ try {
+ $file = id(new PhabricatorFileQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($fragment->getLatestVersion()->getFilePHID()))
+ ->executeOne();
+ if ($file !== null) {
+ $file_uri = $file->getDownloadURI();
+ }
+ } catch (PhabricatorPolicyException $ex) {
+ // The download link won't be usable.
}
}
$header = id(new PHUIHeaderView())
->setHeader($fragment->getName())
->setPolicyObject($fragment)
->setUser($viewer);
+ $can_edit = PhabricatorPolicyFilter::hasCapability(
+ $viewer,
+ $fragment,
+ PhabricatorPolicyCapability::CAN_EDIT);
+
$actions = id(new PhabricatorActionListView())
->setUser($viewer)
->setObject($fragment)
@@ -102,28 +111,39 @@
->setName(pht('Download Fragment'))
->setHref($file_uri)
->setDisabled($file === null)
+ ->setRenderAsForm(true)
+ ->setDownload(true)
+ ->setAnonymous(true)
->setIcon('download'));
$actions->addAction(
id(new PhabricatorActionView())
->setName(pht('Download Contents as ZIP'))
->setHref($this->getApplicationURI("zip/".$fragment->getPath()))
- ->setDisabled(false) // TODO: Policy
->setIcon('zip'));
if (!$fragment->isDirectory()) {
$actions->addAction(
id(new PhabricatorActionView())
->setName(pht('Update Fragment'))
->setHref($this->getApplicationURI("update/".$fragment->getPath()))
- ->setDisabled(false) // TODO: Policy
+ ->setDisabled(!$can_edit)
+ ->setWorkflow(!$can_edit)
->setIcon('edit'));
} else {
$actions->addAction(
id(new PhabricatorActionView())
->setName(pht('Convert to File'))
->setHref($this->getApplicationURI("update/".$fragment->getPath()))
- ->setDisabled(false) // TODO: Policy
+ ->setDisabled(!$can_edit)
+ ->setWorkflow(!$can_edit)
->setIcon('edit'));
}
+ $actions->addAction(
+ id(new PhabricatorActionView())
+ ->setName(pht('Set Fragment Policies'))
+ ->setHref($this->getApplicationURI("policy/".$fragment->getPath()))
+ ->setDisabled(!$can_edit)
+ ->setWorkflow(!$can_edit)
+ ->setIcon('edit'));
if ($is_history_view) {
$actions->addAction(
id(new PhabricatorActionView())
@@ -142,15 +162,17 @@
->setName(pht('Create Snapshot'))
->setHref($this->getApplicationURI(
"snapshot/create/".$fragment->getPath()))
- ->setDisabled(false) // TODO: Policy
+ ->setDisabled(!$can_edit)
+ ->setWorkflow(!$can_edit)
->setIcon('snapshot'));
$actions->addAction(
id(new PhabricatorActionView())
->setName(pht('Promote Snapshot to Here'))
->setHref($this->getApplicationURI(
"snapshot/promote/latest/".$fragment->getPath()))
->setWorkflow(true)
- ->setDisabled(false) // TODO: Policy
+ ->setDisabled(!$can_edit)
+ ->setWorkflow(!$can_edit)
->setIcon('promote'));
$properties = id(new PHUIPropertyListView())
diff --git a/src/applications/phragment/controller/PhragmentHistoryController.php b/src/applications/phragment/controller/PhragmentHistoryController.php
--- a/src/applications/phragment/controller/PhragmentHistoryController.php
+++ b/src/applications/phragment/controller/PhragmentHistoryController.php
@@ -4,6 +4,10 @@
private $dblob;
+ public function shouldAllowPublic() {
+ return true;
+ }
+
public function willProcessRequest(array $data) {
$this->dblob = idx($data, "dblob", "");
}
@@ -21,11 +25,14 @@
$path = $current->getPath();
$crumbs = $this->buildApplicationCrumbsWithPath($parents);
- $crumbs->addAction(
- id(new PHUIListItemView())
- ->setName(pht('Create Fragment'))
- ->setHref($this->getApplicationURI('/create/'.$path))
- ->setIcon('create'));
+ if ($this->hasApplicationCapability(
+ PhragmentCapabilityCanCreate::CAPABILITY)) {
+ $crumbs->addAction(
+ id(new PHUIListItemView())
+ ->setName(pht('Create Fragment'))
+ ->setHref($this->getApplicationURI('/create/'.$path))
+ ->setIcon('create'));
+ }
$current_box = $this->createCurrentFragmentView($current, true);
@@ -44,6 +51,11 @@
->execute();
$files = mpull($files, null, 'getPHID');
+ $can_edit = PhabricatorPolicyFilter::hasCapability(
+ $viewer,
+ $current,
+ PhabricatorPolicyCapability::CAN_EDIT);
+
$first = true;
foreach ($versions as $version) {
$item = id(new PHUIObjectItemView());
@@ -58,7 +70,7 @@
$item->addAttribute('Deletion');
}
- if (!$first) {
+ if (!$first && $can_edit) {
$item->addAction(id(new PHUIListItemView())
->setIcon('undo')
->setRenderNameAsTooltip(true)
@@ -68,16 +80,22 @@
"revert/".$version->getID()."/".$current->getPath())));
}
- $disabled = !isset($files[$version->getFilePHID()]);
- $action = id(new PHUIListItemView())
- ->setIcon('download')
- ->setDisabled($disabled)
- ->setRenderNameAsTooltip(true)
- ->setName(pht("Download"));
- if (!$disabled) {
- $action->setHref($files[$version->getFilePHID()]->getBestURI());
+ // We can't display the download links here for unauthenticated users
+ // as they won't be able to see the info page. If they click through
+ // to the version they can download it from there anyway.
+ if (!$request->getUser()) {
+ $disabled = !isset($files[$version->getFilePHID()]);
+ $action = id(new PHUIListItemView())
+ ->setIcon('download')
+ ->setDisabled($disabled)
+ ->setRenderNameAsTooltip(true)
+ ->setName(pht("Download"));
+ if (!$disabled) {
+ $action->setHref($files[$version->getFilePHID()]->getBestURI());
+ }
+ $item->addAction($action);
}
- $item->addAction($action);
+
$list->addItem($item);
$first = false;
diff --git a/src/applications/phragment/controller/PhragmentPatchController.php b/src/applications/phragment/controller/PhragmentPatchController.php
--- a/src/applications/phragment/controller/PhragmentPatchController.php
+++ b/src/applications/phragment/controller/PhragmentPatchController.php
@@ -5,6 +5,10 @@
private $aid;
private $bid;
+ public function shouldAllowPublic() {
+ return true;
+ }
+
public function willProcessRequest(array $data) {
$this->aid = idx($data, "aid", 0);
$this->bid = idx($data, "bid", 0);
@@ -61,7 +65,9 @@
$patch = PhragmentPatchUtil::calculatePatch($file_a, $file_b);
if ($patch === null) {
- throw new Exception("Unable to compute patch!");
+ // There are no differences between the two files, so we output
+ // an empty patch.
+ $patch = '';
}
$a_sequence = 'x';
@@ -81,6 +87,9 @@
'mime-type' => 'text/plain',
'ttl' => time() + 60 * 60 * 24,
));
+
+ // FIXME: Because Phabricator will deduplicate the file above, the patch
+ // won't necessarily be visible to the user and they'll get a login page :(
return id(new AphrontRedirectResponse())
->setURI($result->getBestURI());
}
diff --git a/src/applications/phragment/controller/PhragmentPolicyController.php b/src/applications/phragment/controller/PhragmentPolicyController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phragment/controller/PhragmentPolicyController.php
@@ -0,0 +1,151 @@
+<?php
+
+final class PhragmentPolicyController extends PhragmentController {
+
+ private $dblob;
+
+ public function willProcessRequest(array $data) {
+ $this->dblob = idx($data, "dblob", "");
+ }
+
+ public function processRequest() {
+ $request = $this->getRequest();
+ $viewer = $request->getUser();
+
+ $parents = $this->loadParentFragments($this->dblob);
+ if ($parents === null) {
+ return new Aphront404Response();
+ }
+ $fragment = idx($parents, count($parents) - 1, null);
+
+ $error_view = null;
+
+ if ($request->isFormPost()) {
+ $errors = array();
+
+ $v_view_policy = $request->getStr('viewPolicy');
+ $v_edit_policy = $request->getStr('editPolicy');
+ $v_replace_children = $request->getBool('replacePoliciesOnChildren');
+ $v_set_file_policy = $request->getBool('setFilePolicies');
+
+ $fragment->setViewPolicy($v_view_policy);
+ $fragment->setEditPolicy($v_edit_policy);
+
+ $fragment->save();
+
+ if ($v_set_file_policy) {
+ $versions = id(new PhragmentFragmentVersionQuery())
+ ->setViewer($viewer)
+ ->withFragmentPHIDs(array($fragment->getPHID()))
+ ->execute();
+ $file_phids = mpull($versions, 'getFilePHID');
+
+ $files = id(new PhabricatorFileQuery())
+ ->setViewer($viewer)
+ ->withPHIDs($file_phids)
+ ->execute();
+ foreach ($files as $file) {
+ $file->setViewPolicy($v_view_policy);
+ $file->save();
+ }
+ }
+
+ if ($v_replace_children) {
+ // If you can edit a fragment, you can forcibly set the policies
+ // on child fragments, regardless of whether you can see them or not.
+ $children = id(new PhragmentFragmentQuery())
+ ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->withLeadingPath($fragment->getPath().'/')
+ ->execute();
+ $children_phids = mpull($children, 'getPHID');
+
+ $fragment->openTransaction();
+ foreach ($children as $child) {
+ $child->setViewPolicy($v_view_policy);
+ $child->setEditPolicy($v_edit_policy);
+ $child->save();
+ }
+ $fragment->saveTransaction();
+
+ if ($v_set_file_policy) {
+ $versions = id(new PhragmentFragmentVersionQuery())
+ ->setViewer($viewer)
+ ->withFragmentPHIDs($children_phids)
+ ->execute();
+ $file_phids = mpull($versions, 'getFilePHID');
+
+ $files = id(new PhabricatorFileQuery())
+ ->setViewer($viewer)
+ ->withPHIDs($file_phids)
+ ->execute();
+ foreach ($files as $file) {
+ $file->setViewPolicy($v_view_policy);
+ $file->save();
+ }
+ }
+ }
+
+ return id(new AphrontRedirectResponse())
+ ->setURI('/phragment/browse/'.$fragment->getPath());
+ }
+
+ $policies = id(new PhabricatorPolicyQuery())
+ ->setViewer($viewer)
+ ->setObject($fragment)
+ ->execute();
+
+ $form = id(new AphrontFormView())
+ ->setUser($viewer)
+ ->appendChild(
+ id(new AphrontFormPolicyControl())
+ ->setName('viewPolicy')
+ ->setPolicyObject($fragment)
+ ->setCapability(PhabricatorPolicyCapability::CAN_VIEW)
+ ->setPolicies($policies))
+ ->appendChild(
+ id(new AphrontFormPolicyControl())
+ ->setName('editPolicy')
+ ->setPolicyObject($fragment)
+ ->setCapability(PhabricatorPolicyCapability::CAN_EDIT)
+ ->setPolicies($policies))
+ ->appendChild(
+ id(new AphrontFormCheckboxControl())
+ ->addCheckbox(
+ 'replacePoliciesOnChildren',
+ 'true',
+ pht(
+ 'Replace policies on child fragments with '.
+ 'the policies above.'))
+ ->addCheckbox(
+ 'setFilePolicies',
+ 'true',
+ pht(
+ 'Replace policies on files associated with all versions '.
+ 'of this fragment. You must have view access to the files '.
+ 'to be able to set their policies.')))
+ ->appendChild(
+ id(new AphrontFormSubmitControl())
+ ->setValue(pht('Save Fragment Policies'))
+ ->addCancelButton(
+ $this->getApplicationURI('browse/'.$fragment->getPath())));
+
+ $crumbs = $this->buildApplicationCrumbsWithPath($parents);
+ $crumbs->addCrumb(
+ id(new PhabricatorCrumbView())
+ ->setName(pht('Edit Fragment Policies')));
+
+ $box = id(new PHUIObjectBoxView())
+ ->setHeaderText(pht('Edit Fragment Policies: %s', $fragment->getPath()))
+ ->setValidationException(null)
+ ->setForm($form);
+
+ return $this->buildApplicationPage(
+ array(
+ $crumbs,
+ $box),
+ array(
+ 'title' => pht('Edit Fragment Policies'),
+ 'device' => true));
+ }
+
+}
diff --git a/src/applications/phragment/controller/PhragmentSnapshotCreateController.php b/src/applications/phragment/controller/PhragmentSnapshotCreateController.php
--- a/src/applications/phragment/controller/PhragmentSnapshotCreateController.php
+++ b/src/applications/phragment/controller/PhragmentSnapshotCreateController.php
@@ -21,6 +21,11 @@
return new Aphront404Response();
}
+ PhabricatorPolicyFilter::requireCapability(
+ $viewer,
+ $fragment,
+ PhabricatorPolicyCapability::CAN_EDIT);
+
$children = id(new PhragmentFragmentQuery())
->setViewer($viewer)
->needLatestVersion(true)
diff --git a/src/applications/phragment/controller/PhragmentSnapshotDeleteController.php b/src/applications/phragment/controller/PhragmentSnapshotDeleteController.php
--- a/src/applications/phragment/controller/PhragmentSnapshotDeleteController.php
+++ b/src/applications/phragment/controller/PhragmentSnapshotDeleteController.php
@@ -20,6 +20,11 @@
return new Aphront404Response();
}
+ PhabricatorPolicyFilter::requireCapability(
+ $viewer,
+ $snapshot,
+ PhabricatorPolicyCapability::CAN_EDIT);
+
if ($request->isDialogFormPost()) {
$fragment_uri = $snapshot->getPrimaryFragment()->getURI();
diff --git a/src/applications/phragment/controller/PhragmentSnapshotPromoteController.php b/src/applications/phragment/controller/PhragmentSnapshotPromoteController.php
--- a/src/applications/phragment/controller/PhragmentSnapshotPromoteController.php
+++ b/src/applications/phragment/controller/PhragmentSnapshotPromoteController.php
@@ -29,6 +29,11 @@
return new Aphront404Response();
}
+ PhabricatorPolicyFilter::requireCapability(
+ $viewer,
+ $this->targetFragment,
+ PhabricatorPolicyCapability::CAN_EDIT);
+
$this->snapshots = id(new PhragmentSnapshotQuery())
->setViewer($viewer)
->withPrimaryFragmentPHIDs(array($this->targetFragment->getPHID()))
@@ -46,6 +51,11 @@
return new Aphront404Response();
}
+ PhabricatorPolicyFilter::requireCapability(
+ $viewer,
+ $this->targetSnapshot,
+ PhabricatorPolicyCapability::CAN_EDIT);
+
$this->snapshots = id(new PhragmentSnapshotQuery())
->setViewer($viewer)
->withPrimaryFragmentPHIDs(array(
diff --git a/src/applications/phragment/controller/PhragmentSnapshotViewController.php b/src/applications/phragment/controller/PhragmentSnapshotViewController.php
--- a/src/applications/phragment/controller/PhragmentSnapshotViewController.php
+++ b/src/applications/phragment/controller/PhragmentSnapshotViewController.php
@@ -4,6 +4,10 @@
private $id;
+ public function shouldAllowPublic() {
+ return true;
+ }
+
public function willProcessRequest(array $data) {
$this->id = idx($data, "id", "");
}
diff --git a/src/applications/phragment/controller/PhragmentVersionController.php b/src/applications/phragment/controller/PhragmentVersionController.php
--- a/src/applications/phragment/controller/PhragmentVersionController.php
+++ b/src/applications/phragment/controller/PhragmentVersionController.php
@@ -4,6 +4,10 @@
private $id;
+ public function shouldAllowPublic() {
+ return true;
+ }
+
public function willProcessRequest(array $data) {
$this->id = idx($data, "id", 0);
}
@@ -41,7 +45,7 @@
->withPHIDs(array($version->getFilePHID()))
->executeOne();
if ($file !== null) {
- $file_uri = $file->getBestURI();
+ $file_uri = $file->getDownloadURI();
}
$header = id(new PHUIHeaderView())
@@ -61,6 +65,9 @@
->setName(pht('Download Version'))
->setHref($file_uri)
->setDisabled($file === null)
+ ->setRenderAsForm(true)
+ ->setDownload(true)
+ ->setAnonymous(true)
->setIcon('download'));
$properties = id(new PHUIPropertyListView())
diff --git a/src/applications/phragment/controller/PhragmentZIPController.php b/src/applications/phragment/controller/PhragmentZIPController.php
--- a/src/applications/phragment/controller/PhragmentZIPController.php
+++ b/src/applications/phragment/controller/PhragmentZIPController.php
@@ -7,6 +7,10 @@
private $snapshotCache;
+ public function shouldAllowPublic() {
+ return true;
+ }
+
public function willProcessRequest(array $data) {
$this->dblob = idx($data, "dblob", "");
$this->snapshot = idx($data, "snapshot", null);
@@ -87,7 +91,9 @@
}
foreach ($mappings as $path => $file) {
- $zip->addFromString($path, $file->loadFileData());
+ if ($file !== null) {
+ $zip->addFromString($path, $file->loadFileData());
+ }
}
$zip->close();
@@ -104,7 +110,7 @@
'ttl' => time() + 60 * 60 * 24,
));
return id(new AphrontRedirectResponse())
- ->setURI($file->getBestURI());
+ ->setURI($file->getNonceURI());
}
/**
diff --git a/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php b/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
--- a/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
+++ b/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
@@ -1828,6 +1828,10 @@
'type' => 'sql',
'name' => $this->getPatchPath('20131208.phragmentsnapshot.sql'),
),
+ '20131210.filenonce.sql' => array(
+ 'type' => 'sql',
+ 'name' => $this->getPatchPath('20131210.filenonce.sql'),
+ ),
);
}
}
diff --git a/src/view/layout/PhabricatorActionView.php b/src/view/layout/PhabricatorActionView.php
--- a/src/view/layout/PhabricatorActionView.php
+++ b/src/view/layout/PhabricatorActionView.php
@@ -11,6 +11,7 @@
private $renderAsForm;
private $download;
private $objectURI;
+ private $anonymous;
public function setObjectURI($object_uri) {
$this->objectURI = $object_uri;
@@ -40,7 +41,7 @@
* viewing.
*/
public function getHref() {
- if ($this->workflow || $this->renderAsForm) {
+ if (($this->workflow || $this->renderAsForm) && !$this->anonymous) {
if (!$this->user || !$this->user->isLoggedIn()) {
return id(new PhutilURI('/auth/start/'))
->setQueryParam('next', (string)$this->getObjectURI());
@@ -75,6 +76,11 @@
return $this;
}
+ public function setAnonymous($anonymous) {
+ $this->anonymous = $anonymous;
+ return $this;
+ }
+
public function setRenderAsForm($form) {
$this->renderAsForm = $form;
return $this;
File Metadata
Details
Attached
Mime Type
text/x-diff
Storage Engine
amazon-s3
Storage Format
Raw Data
Storage Handle
phabricator/cb/3s/e3zancxidid7w3kx
Default Alt Text
D7751.id17532.diff (30 KB)
Attached To
Mode
D7751: Implement policies in Phragment
Attached
Detach File
Event Timeline
Log In to Comment