Provide an attached-to-visible-object policy exception for files

Summary:
Ref T603. This uses the existing edges (from Conpherence) to record that a file is attached to an object, and uses those edges to create a policy exception: if you can view an attached object, you can view a file.

I'm going to combine this with restrictive defaults to satisfy the other half of the equation (that files you attach to a conpherence usually shouldn't be public by default).

Test Plan:
  - Loaded `/files/`.
  - Uploaded a file to a Conpherence, looked at it in Files, saw the attachment.

Reviewers: btrahan

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T603

Differential Revision: https://secure.phabricator.com/D7182
This commit is contained in:
epriestley
2013-10-01 08:43:34 -07:00
parent fc57995330
commit 472be5e26e
3 changed files with 105 additions and 3 deletions

View File

@@ -27,7 +27,11 @@ final class PhabricatorFileInfoController extends PhabricatorFileController {
->withObjectPHIDs(array($phid)) ->withObjectPHIDs(array($phid))
->execute(); ->execute();
$this->loadHandles(array($file->getAuthorPHID())); $handle_phids = array_merge(
array($file->getAuthorPHID()),
$file->getObjectPHIDs());
$this->loadHandles($handle_phids);
$header = id(new PHUIHeaderView()) $header = id(new PHUIHeaderView())
->setHeader($file->getName()); ->setHeader($file->getName());
@@ -207,6 +211,15 @@ final class PhabricatorFileInfoController extends PhabricatorFileController {
} }
} }
$phids = $file->getObjectPHIDs();
if ($phids) {
$view->addSectionHeader(pht('Attached'));
$view->addProperty(
pht('Attached To'),
$this->renderHandlesForPHIDs($phids));
}
if ($file->isViewableImage()) { if ($file->isViewableImage()) {
$image = phutil_tag( $image = phutil_tag(

View File

@@ -104,7 +104,48 @@ final class PhabricatorFileQuery
$this->buildOrderClause($conn_r), $this->buildOrderClause($conn_r),
$this->buildLimitClause($conn_r)); $this->buildLimitClause($conn_r));
return $table->loadAllFromArray($data); $files = $table->loadAllFromArray($data);
if (!$files) {
return $files;
}
// We need to load attached objects to perform policy checks for files.
// First, load the edges.
$edge_type = PhabricatorEdgeConfig::TYPE_FILE_HAS_OBJECT;
$phids = mpull($files, 'getPHID');
$edges = id(new PhabricatorEdgeQuery())
->withSourcePHIDs($phids)
->withEdgeTypes(array($edge_type))
->execute();
$object_phids = array();
foreach ($files as $file) {
$phids = array_keys($edges[$file->getPHID()][$edge_type]);
$file->attachObjectPHIDs($phids);
foreach ($phids as $phid) {
$object_phids[$phid] = true;
}
}
// Now, load the objects.
$objects = array();
if ($object_phids) {
$objects = id(new PhabricatorObjectQuery())
->setViewer($this->getViewer())
->withPHIDs($object_phids)
->execute();
$objects = mpull($objects, null, 'getPHID');
}
foreach ($files as $file) {
$file_objects = array_select_keys($objects, $file->getObjectPHIDs());
$file->attachObjects($file_objects);
}
return $files;
} }
private function buildJoinClause(AphrontDatabaseConnection $conn_r) { private function buildJoinClause(AphrontDatabaseConnection $conn_r) {

View File

@@ -31,6 +31,9 @@ final class PhabricatorFile extends PhabricatorFileDAO
protected $ttl; protected $ttl;
protected $isExplicitUpload = 1; protected $isExplicitUpload = 1;
private $objects = self::ATTACHABLE;
private $objectPHIDs = self::ATTACHABLE;
public function getConfiguration() { public function getConfiguration() {
return array( return array(
self::CONFIG_AUX_PHID => true, self::CONFIG_AUX_PHID => true,
@@ -803,6 +806,9 @@ final class PhabricatorFile extends PhabricatorFileDAO
->save(); ->save();
unset($unguarded); unset($unguarded);
$file->attachObjectPHIDs(array());
$file->attachObjects(array());
$files[$name] = $file; $files[$name] = $file;
} }
@@ -821,6 +827,24 @@ final class PhabricatorFile extends PhabricatorFileDAO
return idx(self::loadBuiltins($user, array($name)), $name); return idx(self::loadBuiltins($user, array($name)), $name);
} }
public function getObjects() {
return $this->assertAttached($this->objects);
}
public function attachObjects(array $objects) {
$this->objects = $objects;
return $this;
}
public function getObjectPHIDs() {
return $this->assertAttached($this->objectPHIDs);
}
public function attachObjectPHIDs(array $object_phids) {
$this->objectPHIDs = $object_phids;
return $this;
}
/* -( PhabricatorPolicyInterface Implementation )-------------------------- */ /* -( PhabricatorPolicyInterface Implementation )-------------------------- */
@@ -838,11 +862,35 @@ final class PhabricatorFile extends PhabricatorFileDAO
} }
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
$viewer_phid = $viewer->getPHID();
if ($viewer_phid) {
if ($this->getAuthorPHID() == $viewer_phid) {
return true;
}
}
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
// If you can see any object this file is attached to, you can see
// the file.
return (count($this->getObjects()) > 0);
}
return false; return false;
} }
public function describeAutomaticCapability($capability) { public function describeAutomaticCapability($capability) {
return null; $out = array();
$out[] = pht('The user who uploaded a file can always view and edit it.');
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
$out[] = pht(
'Files attached to objects are visible to users who can view '.
'those objects.');
break;
}
return $out;
} }