1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-25 08:12:40 +01:00

Add a CanCDN flag to uploaded files

Summary:
CanCDN flag indicates that a file can be served + cached
via anonymous content distribution networks.

Once D10054 lands, any files that lack the CanCDN flag
will require a one-time-use token and headers will
prohibit cache to protect sensitive files from
unauthorized access.

This diff separates the CanCDN changes from the code that
enforces these restrictions in D10054 so that the changes
can be tested and refined independently.

Test Plan: Work in progress

Reviewers: #blessed_reviewers, epriestley

Reviewed By: #blessed_reviewers, epriestley

Subscribers: rush898, qgil, epriestley, aklapper, Korvin

Maniphest Tasks: T5685

Differential Revision: https://secure.phabricator.com/D10166
This commit is contained in:
Mukunda Modell 2014-08-07 18:56:19 -07:00 committed by epriestley
parent c0585b7a34
commit 12aaa942ac
8 changed files with 75 additions and 1 deletions

View file

@ -52,6 +52,7 @@ $file = PhabricatorFile::newFromFileData(
$data,
array(
'name' => basename($path),
'canCDN' => true,
));
$macro = id(new PhabricatorFileImageMacro())

View file

@ -243,6 +243,7 @@ abstract class PhabricatorAuthProvider {
$image_uri,
array(
'name' => $name,
'canCDN' => true
));
unset($unguarded);

View file

@ -16,6 +16,7 @@ final class PhabricatorImageTransformer {
array(
'name' => 'meme-'.$file->getName(),
'ttl' => time() + 60 * 60 * 24,
'canCDN' => true,
));
}
@ -30,6 +31,7 @@ final class PhabricatorImageTransformer {
$image,
array(
'name' => 'thumb-'.$file->getName(),
'canCDN' => true,
));
}
@ -45,6 +47,7 @@ final class PhabricatorImageTransformer {
$image,
array(
'name' => 'profile-'.$file->getName(),
'canCDN' => true,
));
}
@ -58,6 +61,7 @@ final class PhabricatorImageTransformer {
$image,
array(
'name' => 'preview-'.$file->getName(),
'canCDN' => true,
));
}
@ -79,6 +83,7 @@ final class PhabricatorImageTransformer {
$image,
array(
'name' => 'conpherence-'.$file->getName(),
'canCDN' => true,
));
}

View file

@ -38,6 +38,7 @@ final class PhabricatorFileComposeController
$data,
array(
'name' => 'project.png',
'canCDN' => true,
));
$content = array(

View file

@ -7,10 +7,12 @@ final class PhabricatorFile extends PhabricatorFileDAO
PhabricatorFlaggableInterface,
PhabricatorPolicyInterface {
const ONETIME_TEMPORARY_TOKEN_TYPE = 'file:onetime';
const STORAGE_FORMAT_RAW = 'raw';
const METADATA_IMAGE_WIDTH = 'width';
const METADATA_IMAGE_HEIGHT = 'height';
const METADATA_CAN_CDN = 'cancdn';
protected $name;
protected $mimeType;
@ -202,7 +204,6 @@ final class PhabricatorFile extends PhabricatorFileDAO
}
private static function buildFromFileData($data, array $params = array()) {
$selector = PhabricatorEnv::newObjectFromConfig('storage.engine-selector');
if (isset($params['storageEngines'])) {
$engines = $params['storageEngines'];
@ -270,6 +271,10 @@ final class PhabricatorFile extends PhabricatorFileDAO
$file->setViewPolicy($params['viewPolicy']);
}
if (idx($params, 'canCDN')) {
$file->setCanCDN(true);
}
$file->setStorageEngine($engine_identifier);
$file->setStorageHandle($data_handle);
@ -852,6 +857,63 @@ final class PhabricatorFile extends PhabricatorFileDAO
return idx($this->metadata, self::METADATA_IMAGE_WIDTH);
}
public function getCanCDN() {
if (!$this->isViewableImage()) {
return false;
}
return idx($this->metadata, self::METADATA_CAN_CDN);
}
public function setCanCDN($can_cdn) {
$this->metadata[self::METADATA_CAN_CDN] = $can_cdn ? 1 : 0;
return $this;
}
protected function generateOneTimeToken() {
$key = Filesystem::readRandomCharacters(16);
// Save the new secret.
return id(new PhabricatorAuthTemporaryToken())
->setObjectPHID($this->getPHID())
->setTokenType(self::ONETIME_TEMPORARY_TOKEN_TYPE)
->setTokenExpires(time() + phutil_units('1 hour in seconds'))
->setTokenCode(PhabricatorHash::digest($key))
->save();
}
public function validateOneTimeToken($token_code) {
$token = id(new PhabricatorAuthTemporaryTokenQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withObjectPHIDs(array($this->getPHID()))
->withTokenTypes(array(self::ONETIME_TEMPORARY_TOKEN_TYPE))
->withExpired(false)
->withTokenCodes(array($token_code))
->executeOne();
return $token;
}
/** Get the CDN uri for this file
* This will generate a one-time-use token if
* security.alternate_file_domain is set in the config.
*/
public function getCDNURIWithToken() {
if (!$this->getPHID()) {
throw new Exception(
'You must save a file before you can generate a CDN URI.');
}
$name = phutil_escape_uri($this->getName());
$path = '/file/data'
.'/'.$this->getSecretKey()
.'/'.$this->getPHID()
.'/'.$this->generateOneTimeToken()
.'/'.$name;
return PhabricatorEnv::getCDNURI($path);
}
/**
* Write the policy edge between this file and some object.
*

View file

@ -64,6 +64,7 @@ final class PhabricatorMacroEditController extends PhabricatorMacroController {
'name' => $request->getStr('name'),
'authorPHID' => $user->getPHID(),
'isExplicitUpload' => true,
'canCDN' => true,
));
} else if ($request->getStr('url')) {
try {
@ -73,6 +74,7 @@ final class PhabricatorMacroEditController extends PhabricatorMacroController {
'name' => $request->getStr('name'),
'authorPHID' => $user->getPHID(),
'isExplicitUpload' => true,
'canCDN' => true,
));
} catch (Exception $ex) {
$errors[] = pht('Could not fetch URL: %s', $ex->getMessage());

View file

@ -53,6 +53,7 @@ final class PhabricatorPeopleProfilePictureController
$_FILES['picture'],
array(
'authorPHID' => $viewer->getPHID(),
'canCDN' => true,
));
} else {
$e_file = pht('Required');

View file

@ -50,6 +50,7 @@ final class PhabricatorProjectEditPictureController
$_FILES['picture'],
array(
'authorPHID' => $viewer->getPHID(),
'canCDN' => true,
));
} else {
$e_file = pht('Required');