2011-01-23 03:33:00 +01:00
|
|
|
<?php
|
|
|
|
|
Move ALL files to serve from the alternate file domain, not just files without
"Content-Disposition: attachment"
Summary:
We currently serve some files off the primary domain (with "Content-Disposition:
attachment" + a CSRF check) and some files off the alternate domain (without
either).
This is not sufficient, because some UAs (like the iPad) ignore
"Content-Disposition: attachment". So there's an attack that goes like this:
- Alice uploads xss.html
- Alice says to Bob "hey download this file on your iPad"
- Bob clicks "Download" on Phabricator on his iPad, gets XSS'd.
NOTE: This removes the CSRF check for downloading files. The check is nice to
have but only raises the barrier to entry slightly. Between iPad / sniffing /
flash bytecode attacks, single-domain installs are simply insecure. We could
restore the check at some point in conjunction with a derived authentication
cookie (i.e., a mini-session-token which is only useful for downloading files),
but that's a lot of complexity to drop all at once.
(Because files are now authenticated only by knowing the PHID and secret key,
this also fixes the "no profile pictures in public feed while logged out"
issue.)
Test Plan: Viewed, info'd, and downloaded files
Reviewers: btrahan, arice, alok
Reviewed By: arice
CC: aran, epriestley
Maniphest Tasks: T843
Differential Revision: https://secure.phabricator.com/D1608
2012-02-14 23:52:27 +01:00
|
|
|
final class PhabricatorFileInfoController extends PhabricatorFileController {
|
2011-01-23 03:33:00 +01:00
|
|
|
|
|
|
|
private $phid;
|
2014-08-20 22:18:21 +02:00
|
|
|
private $id;
|
|
|
|
|
|
|
|
public function shouldAllowPublic() {
|
|
|
|
return true;
|
|
|
|
}
|
2011-01-23 03:33:00 +01:00
|
|
|
|
|
|
|
public function willProcessRequest(array $data) {
|
2014-08-20 22:18:21 +02:00
|
|
|
$this->phid = idx($data, 'phid');
|
|
|
|
$this->id = idx($data, 'id');
|
2011-01-23 03:33:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public function processRequest() {
|
Use phabricator_ time functions in more places
Summary:
Replace some more date() calls with locale-aware calls.
Also, at least on my system, the DateTimeZone / DateTime stuff didn't actually
work and always rendered in UTC. Fixed that.
Test Plan:
Viewed daemon console, differential revisions, files, and maniphest timestamps
in multiple timezones.
Reviewed By: toulouse
Reviewers: toulouse, fratrik, jungejason, aran, tuomaspelkonen
CC: aran, toulouse
Differential Revision: 530
2011-06-26 18:22:52 +02:00
|
|
|
$request = $this->getRequest();
|
|
|
|
$user = $request->getUser();
|
|
|
|
|
2014-08-20 22:18:21 +02:00
|
|
|
if ($this->phid) {
|
|
|
|
$file = id(new PhabricatorFileQuery())
|
|
|
|
->setViewer($user)
|
|
|
|
->withPHIDs(array($this->phid))
|
|
|
|
->executeOne();
|
|
|
|
|
|
|
|
if (!$file) {
|
|
|
|
return new Aphront404Response();
|
|
|
|
}
|
|
|
|
return id(new AphrontRedirectResponse())->setURI($file->getInfoURI());
|
|
|
|
}
|
2012-12-17 01:33:24 +01:00
|
|
|
$file = id(new PhabricatorFileQuery())
|
|
|
|
->setViewer($user)
|
2014-08-20 22:18:21 +02:00
|
|
|
->withIDs(array($this->id))
|
2012-12-17 01:33:24 +01:00
|
|
|
->executeOne();
|
2011-01-23 03:33:00 +01:00
|
|
|
if (!$file) {
|
|
|
|
return new Aphront404Response();
|
|
|
|
}
|
2011-02-22 18:22:57 +01:00
|
|
|
|
2012-12-17 01:33:24 +01:00
|
|
|
$phid = $file->getPHID();
|
2013-09-05 22:11:02 +02:00
|
|
|
$xactions = id(new PhabricatorFileTransactionQuery())
|
|
|
|
->setViewer($user)
|
|
|
|
->withObjectPHIDs(array($phid))
|
|
|
|
->execute();
|
|
|
|
|
2013-10-01 17:43:34 +02:00
|
|
|
$handle_phids = array_merge(
|
|
|
|
array($file->getAuthorPHID()),
|
|
|
|
$file->getObjectPHIDs());
|
|
|
|
|
|
|
|
$this->loadHandles($handle_phids);
|
2013-09-17 18:12:37 +02:00
|
|
|
$header = id(new PHUIHeaderView())
|
2013-12-30 20:27:02 +01:00
|
|
|
->setUser($user)
|
|
|
|
->setPolicyObject($file)
|
2012-12-17 01:33:24 +01:00
|
|
|
->setHeader($file->getName());
|
|
|
|
|
2013-02-20 22:33:47 +01:00
|
|
|
$ttl = $file->getTTL();
|
|
|
|
if ($ttl !== null) {
|
2014-01-14 23:09:52 +01:00
|
|
|
$ttl_tag = id(new PHUITagView())
|
|
|
|
->setType(PHUITagView::TYPE_OBJECT)
|
2014-06-09 20:36:49 +02:00
|
|
|
->setName(pht('Temporary'));
|
2013-02-20 22:33:47 +01:00
|
|
|
$header->addTag($ttl_tag);
|
|
|
|
}
|
|
|
|
|
2012-12-17 01:33:24 +01:00
|
|
|
$actions = $this->buildActionView($file);
|
2013-09-05 22:11:02 +02:00
|
|
|
$timeline = $this->buildTransactionView($file, $xactions);
|
2013-04-10 22:08:36 +02:00
|
|
|
$crumbs = $this->buildApplicationCrumbs();
|
|
|
|
$crumbs->setActionList($actions);
|
2013-12-19 02:47:34 +01:00
|
|
|
$crumbs->addTextCrumb(
|
|
|
|
'F'.$file->getID(),
|
|
|
|
$this->getApplicationURI("/info/{$phid}/"));
|
2013-04-10 22:08:36 +02:00
|
|
|
|
2013-09-29 00:55:38 +02:00
|
|
|
$object_box = id(new PHUIObjectBoxView())
|
2013-10-11 16:53:56 +02:00
|
|
|
->setHeader($header);
|
|
|
|
|
2013-10-19 21:08:06 +02:00
|
|
|
$this->buildPropertyViews($object_box, $file, $actions);
|
2013-09-29 00:55:38 +02:00
|
|
|
|
2012-12-17 01:33:24 +01:00
|
|
|
return $this->buildApplicationPage(
|
|
|
|
array(
|
|
|
|
$crumbs,
|
2013-09-29 00:55:38 +02:00
|
|
|
$object_box,
|
2013-09-05 22:11:02 +02:00
|
|
|
$timeline
|
2012-12-17 01:33:24 +01:00
|
|
|
),
|
|
|
|
array(
|
|
|
|
'title' => $file->getName(),
|
2013-09-05 22:11:02 +02:00
|
|
|
'pageObjects' => array($file->getPHID()),
|
2012-12-17 01:33:24 +01:00
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2013-09-05 22:11:02 +02:00
|
|
|
private function buildTransactionView(
|
|
|
|
PhabricatorFile $file,
|
|
|
|
array $xactions) {
|
|
|
|
|
|
|
|
$user = $this->getRequest()->getUser();
|
|
|
|
$engine = id(new PhabricatorMarkupEngine())
|
|
|
|
->setViewer($user);
|
|
|
|
foreach ($xactions as $xaction) {
|
|
|
|
if ($xaction->getComment()) {
|
|
|
|
$engine->addObject(
|
|
|
|
$xaction->getComment(),
|
|
|
|
PhabricatorApplicationTransactionComment::MARKUP_FIELD_COMMENT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$engine->process();
|
|
|
|
|
|
|
|
$timeline = id(new PhabricatorApplicationTransactionView())
|
|
|
|
->setUser($user)
|
|
|
|
->setObjectPHID($file->getPHID())
|
|
|
|
->setTransactions($xactions)
|
|
|
|
->setMarkupEngine($engine);
|
|
|
|
|
|
|
|
$is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
|
|
|
|
|
2013-11-22 01:09:04 +01:00
|
|
|
$add_comment_header = $is_serious
|
|
|
|
? pht('Add Comment')
|
|
|
|
: pht('Question File Integrity');
|
2013-09-05 22:11:02 +02:00
|
|
|
|
|
|
|
$draft = PhabricatorDraft::newFromUserAndKey($user, $file->getPHID());
|
|
|
|
|
|
|
|
$add_comment_form = id(new PhabricatorApplicationTransactionCommentView())
|
|
|
|
->setUser($user)
|
|
|
|
->setObjectPHID($file->getPHID())
|
|
|
|
->setDraft($draft)
|
2013-11-22 01:09:04 +01:00
|
|
|
->setHeaderText($add_comment_header)
|
2013-09-05 22:11:02 +02:00
|
|
|
->setAction($this->getApplicationURI('/comment/'.$file->getID().'/'))
|
2014-04-19 02:51:46 +02:00
|
|
|
->setSubmitButtonName(pht('Add Comment'));
|
2013-09-05 22:11:02 +02:00
|
|
|
|
|
|
|
return array(
|
|
|
|
$timeline,
|
2013-11-22 01:09:04 +01:00
|
|
|
$add_comment_form);
|
2013-09-05 22:11:02 +02:00
|
|
|
}
|
|
|
|
|
2012-12-17 01:33:24 +01:00
|
|
|
private function buildActionView(PhabricatorFile $file) {
|
|
|
|
$request = $this->getRequest();
|
2014-08-02 23:45:50 +02:00
|
|
|
$viewer = $request->getUser();
|
2011-07-08 06:17:00 +02:00
|
|
|
|
2012-12-17 01:33:24 +01:00
|
|
|
$id = $file->getID();
|
2011-02-22 18:22:57 +01:00
|
|
|
|
2014-08-02 23:45:50 +02:00
|
|
|
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
|
|
|
$viewer,
|
|
|
|
$file,
|
|
|
|
PhabricatorPolicyCapability::CAN_EDIT);
|
|
|
|
|
2012-12-17 01:33:24 +01:00
|
|
|
$view = id(new PhabricatorActionListView())
|
2014-08-02 23:45:50 +02:00
|
|
|
->setUser($viewer)
|
2013-07-12 20:39:47 +02:00
|
|
|
->setObjectURI($this->getRequest()->getRequestURI())
|
2012-12-17 01:33:24 +01:00
|
|
|
->setObject($file);
|
2012-01-16 22:26:44 +01:00
|
|
|
|
2011-02-22 18:19:14 +01:00
|
|
|
if ($file->isViewableInBrowser()) {
|
2012-12-17 01:33:24 +01:00
|
|
|
$view->addAction(
|
|
|
|
id(new PhabricatorActionView())
|
|
|
|
->setName(pht('View File'))
|
2014-05-13 16:45:39 +02:00
|
|
|
->setIcon('fa-file-o')
|
2012-12-17 01:33:24 +01:00
|
|
|
->setHref($file->getViewURI()));
|
2011-02-22 18:19:14 +01:00
|
|
|
} else {
|
2012-12-17 01:33:24 +01:00
|
|
|
$view->addAction(
|
|
|
|
id(new PhabricatorActionView())
|
2014-08-02 23:45:50 +02:00
|
|
|
->setUser($viewer)
|
2012-12-17 01:33:24 +01:00
|
|
|
->setRenderAsForm(true)
|
2013-01-29 03:12:09 +01:00
|
|
|
->setDownload(true)
|
2012-12-17 01:33:24 +01:00
|
|
|
->setName(pht('Download File'))
|
2014-05-13 16:45:39 +02:00
|
|
|
->setIcon('fa-download')
|
2012-12-17 01:33:24 +01:00
|
|
|
->setHref($file->getViewURI()));
|
2012-01-16 22:26:44 +01:00
|
|
|
}
|
|
|
|
|
2014-08-02 23:45:50 +02:00
|
|
|
$view->addAction(
|
|
|
|
id(new PhabricatorActionView())
|
|
|
|
->setName(pht('Edit File'))
|
|
|
|
->setIcon('fa-pencil')
|
|
|
|
->setHref($this->getApplicationURI("/edit/{$id}/"))
|
|
|
|
->setWorkflow(!$can_edit)
|
|
|
|
->setDisabled(!$can_edit));
|
|
|
|
|
2012-12-17 01:33:24 +01:00
|
|
|
$view->addAction(
|
|
|
|
id(new PhabricatorActionView())
|
|
|
|
->setName(pht('Delete File'))
|
2014-05-13 16:45:39 +02:00
|
|
|
->setIcon('fa-times')
|
2012-12-17 01:33:24 +01:00
|
|
|
->setHref($this->getApplicationURI("/delete/{$id}/"))
|
2014-08-02 23:45:50 +02:00
|
|
|
->setWorkflow(true)
|
|
|
|
->setDisabled(!$can_edit));
|
2012-12-17 01:33:24 +01:00
|
|
|
|
|
|
|
return $view;
|
|
|
|
}
|
|
|
|
|
2013-10-19 21:08:06 +02:00
|
|
|
private function buildPropertyViews(
|
|
|
|
PHUIObjectBoxView $box,
|
2013-10-11 16:53:56 +02:00
|
|
|
PhabricatorFile $file,
|
|
|
|
PhabricatorActionListView $actions) {
|
2012-12-17 01:33:24 +01:00
|
|
|
$request = $this->getRequest();
|
|
|
|
$user = $request->getUser();
|
|
|
|
|
2013-10-19 21:08:06 +02:00
|
|
|
|
2013-10-11 16:53:56 +02:00
|
|
|
$properties = id(new PHUIPropertyListView());
|
|
|
|
$properties->setActionList($actions);
|
2013-10-19 21:08:06 +02:00
|
|
|
$box->addPropertyList($properties, pht('Details'));
|
2012-12-17 01:33:24 +01:00
|
|
|
|
|
|
|
if ($file->getAuthorPHID()) {
|
2013-10-11 16:53:56 +02:00
|
|
|
$properties->addProperty(
|
2012-12-17 01:33:24 +01:00
|
|
|
pht('Author'),
|
|
|
|
$this->getHandle($file->getAuthorPHID())->renderLink());
|
2011-02-22 18:19:14 +01:00
|
|
|
}
|
2011-07-30 01:01:59 +02:00
|
|
|
|
2013-10-11 16:53:56 +02:00
|
|
|
$properties->addProperty(
|
2012-12-17 01:33:24 +01:00
|
|
|
pht('Created'),
|
|
|
|
phabricator_datetime($file->getDateCreated(), $user));
|
|
|
|
|
2013-10-19 21:08:06 +02:00
|
|
|
|
|
|
|
$finfo = id(new PHUIPropertyListView());
|
|
|
|
$box->addPropertyList($finfo, pht('File Info'));
|
|
|
|
|
|
|
|
$finfo->addProperty(
|
2012-12-17 01:33:24 +01:00
|
|
|
pht('Size'),
|
2014-07-13 04:03:17 +02:00
|
|
|
phutil_format_bytes($file->getByteSize()));
|
2012-12-17 01:33:24 +01:00
|
|
|
|
2013-10-19 21:08:06 +02:00
|
|
|
$finfo->addProperty(
|
2012-12-17 01:33:24 +01:00
|
|
|
pht('Mime Type'),
|
2013-01-29 20:01:47 +01:00
|
|
|
$file->getMimeType());
|
2012-12-17 01:33:24 +01:00
|
|
|
|
2013-10-19 21:08:06 +02:00
|
|
|
$width = $file->getImageWidth();
|
|
|
|
if ($width) {
|
|
|
|
$finfo->addProperty(
|
|
|
|
pht('Width'),
|
|
|
|
pht('%s px', new PhutilNumber($width)));
|
|
|
|
}
|
|
|
|
|
|
|
|
$height = $file->getImageHeight();
|
|
|
|
if ($height) {
|
|
|
|
$finfo->addProperty(
|
|
|
|
pht('Height'),
|
|
|
|
pht('%s px', new PhutilNumber($height)));
|
|
|
|
}
|
|
|
|
|
2014-08-14 21:13:26 +02:00
|
|
|
$is_image = $file->isViewableImage();
|
|
|
|
if ($is_image) {
|
|
|
|
$image_string = pht('Yes');
|
|
|
|
$cache_string = $file->getCanCDN() ? pht('Yes') : pht('No');
|
|
|
|
} else {
|
|
|
|
$image_string = pht('No');
|
|
|
|
$cache_string = pht('Not Applicable');
|
|
|
|
}
|
|
|
|
|
|
|
|
$finfo->addProperty(pht('Viewable Image'), $image_string);
|
|
|
|
$finfo->addProperty(pht('Cacheable'), $cache_string);
|
2013-10-19 21:08:06 +02:00
|
|
|
|
|
|
|
$storage_properties = new PHUIPropertyListView();
|
|
|
|
$box->addPropertyList($storage_properties, pht('Storage'));
|
|
|
|
|
|
|
|
$storage_properties->addProperty(
|
2012-12-17 01:33:24 +01:00
|
|
|
pht('Engine'),
|
2013-01-29 20:01:47 +01:00
|
|
|
$file->getStorageEngine());
|
2012-12-17 01:33:24 +01:00
|
|
|
|
2013-10-19 21:08:06 +02:00
|
|
|
$storage_properties->addProperty(
|
2012-12-17 01:33:24 +01:00
|
|
|
pht('Format'),
|
2013-01-29 20:01:47 +01:00
|
|
|
$file->getStorageFormat());
|
2012-12-17 01:33:24 +01:00
|
|
|
|
2013-10-19 21:08:06 +02:00
|
|
|
$storage_properties->addProperty(
|
2012-12-17 01:33:24 +01:00
|
|
|
pht('Handle'),
|
2013-01-29 20:01:47 +01:00
|
|
|
$file->getStorageHandle());
|
2012-12-17 01:33:24 +01:00
|
|
|
|
2013-01-07 18:43:35 +01:00
|
|
|
|
2013-10-01 17:43:34 +02:00
|
|
|
$phids = $file->getObjectPHIDs();
|
|
|
|
if ($phids) {
|
2013-10-11 16:53:56 +02:00
|
|
|
$attached = new PHUIPropertyListView();
|
2013-10-19 21:08:06 +02:00
|
|
|
$box->addPropertyList($attached, pht('Attached'));
|
|
|
|
|
2013-10-11 16:53:56 +02:00
|
|
|
$attached->addProperty(
|
2013-10-01 17:43:34 +02:00
|
|
|
pht('Attached To'),
|
|
|
|
$this->renderHandlesForPHIDs($phids));
|
|
|
|
}
|
|
|
|
|
2012-12-17 01:33:24 +01:00
|
|
|
|
2013-10-19 21:08:06 +02:00
|
|
|
if ($file->isViewableImage()) {
|
2013-01-18 03:39:02 +01:00
|
|
|
$image = phutil_tag(
|
2012-12-17 01:33:24 +01:00
|
|
|
'img',
|
2012-01-16 15:54:08 +01:00
|
|
|
array(
|
2012-12-17 01:33:24 +01:00
|
|
|
'src' => $file->getViewURI(),
|
2013-10-11 16:53:56 +02:00
|
|
|
'class' => 'phui-property-list-image',
|
2012-01-16 15:54:08 +01:00
|
|
|
));
|
|
|
|
|
2013-01-18 09:32:58 +01:00
|
|
|
$linked_image = phutil_tag(
|
2012-12-17 01:33:24 +01:00
|
|
|
'a',
|
|
|
|
array(
|
|
|
|
'href' => $file->getViewURI(),
|
|
|
|
),
|
|
|
|
$image);
|
|
|
|
|
2013-10-11 16:53:56 +02:00
|
|
|
$media = id(new PHUIPropertyListView())
|
|
|
|
->addImageContent($linked_image);
|
2013-10-19 21:08:06 +02:00
|
|
|
|
|
|
|
$box->addPropertyList($media);
|
2013-09-27 19:51:25 +02:00
|
|
|
} else if ($file->isAudio()) {
|
|
|
|
$audio = phutil_tag(
|
|
|
|
'audio',
|
|
|
|
array(
|
|
|
|
'controls' => 'controls',
|
2013-10-11 16:53:56 +02:00
|
|
|
'class' => 'phui-property-list-audio',
|
2013-09-27 19:51:25 +02:00
|
|
|
),
|
|
|
|
phutil_tag(
|
|
|
|
'source',
|
|
|
|
array(
|
|
|
|
'src' => $file->getViewURI(),
|
|
|
|
'type' => $file->getMimeType(),
|
|
|
|
)));
|
2013-10-11 16:53:56 +02:00
|
|
|
$media = id(new PHUIPropertyListView())
|
|
|
|
->addImageContent($audio);
|
2011-05-22 23:40:51 +02:00
|
|
|
|
2013-10-19 21:08:06 +02:00
|
|
|
$box->addPropertyList($media);
|
|
|
|
}
|
2011-01-23 03:33:00 +01:00
|
|
|
}
|
2012-12-17 01:33:24 +01:00
|
|
|
|
2011-01-23 03:33:00 +01:00
|
|
|
}
|