diff --git a/scripts/util/add_macro.php b/scripts/util/add_macro.php index e2b9ea5608..cbfe8480f6 100755 --- a/scripts/util/add_macro.php +++ b/scripts/util/add_macro.php @@ -52,6 +52,7 @@ $file = PhabricatorFile::newFromFileData( $data, array( 'name' => basename($path), + 'canCDN' => true, )); $macro = id(new PhabricatorFileImageMacro()) diff --git a/src/applications/auth/provider/PhabricatorAuthProvider.php b/src/applications/auth/provider/PhabricatorAuthProvider.php index 0c7948ed1b..9daae24df1 100644 --- a/src/applications/auth/provider/PhabricatorAuthProvider.php +++ b/src/applications/auth/provider/PhabricatorAuthProvider.php @@ -243,6 +243,7 @@ abstract class PhabricatorAuthProvider { $image_uri, array( 'name' => $name, + 'canCDN' => true )); unset($unguarded); diff --git a/src/applications/files/PhabricatorImageTransformer.php b/src/applications/files/PhabricatorImageTransformer.php index 586583c2b3..e13494dd67 100644 --- a/src/applications/files/PhabricatorImageTransformer.php +++ b/src/applications/files/PhabricatorImageTransformer.php @@ -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, )); } diff --git a/src/applications/files/controller/PhabricatorFileComposeController.php b/src/applications/files/controller/PhabricatorFileComposeController.php index ec27ea836a..d698509e96 100644 --- a/src/applications/files/controller/PhabricatorFileComposeController.php +++ b/src/applications/files/controller/PhabricatorFileComposeController.php @@ -38,6 +38,7 @@ final class PhabricatorFileComposeController $data, array( 'name' => 'project.png', + 'canCDN' => true, )); $content = array( diff --git a/src/applications/files/storage/PhabricatorFile.php b/src/applications/files/storage/PhabricatorFile.php index 5e45d8f62c..5ba04f8838 100644 --- a/src/applications/files/storage/PhabricatorFile.php +++ b/src/applications/files/storage/PhabricatorFile.php @@ -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. * diff --git a/src/applications/macro/controller/PhabricatorMacroEditController.php b/src/applications/macro/controller/PhabricatorMacroEditController.php index 79393c7536..5442754e42 100644 --- a/src/applications/macro/controller/PhabricatorMacroEditController.php +++ b/src/applications/macro/controller/PhabricatorMacroEditController.php @@ -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()); diff --git a/src/applications/people/controller/PhabricatorPeopleProfilePictureController.php b/src/applications/people/controller/PhabricatorPeopleProfilePictureController.php index afee9ea84f..55cfb8731c 100644 --- a/src/applications/people/controller/PhabricatorPeopleProfilePictureController.php +++ b/src/applications/people/controller/PhabricatorPeopleProfilePictureController.php @@ -53,6 +53,7 @@ final class PhabricatorPeopleProfilePictureController $_FILES['picture'], array( 'authorPHID' => $viewer->getPHID(), + 'canCDN' => true, )); } else { $e_file = pht('Required'); diff --git a/src/applications/project/controller/PhabricatorProjectEditPictureController.php b/src/applications/project/controller/PhabricatorProjectEditPictureController.php index 6170d6dfa0..98282407be 100644 --- a/src/applications/project/controller/PhabricatorProjectEditPictureController.php +++ b/src/applications/project/controller/PhabricatorProjectEditPictureController.php @@ -50,6 +50,7 @@ final class PhabricatorProjectEditPictureController $_FILES['picture'], array( 'authorPHID' => $viewer->getPHID(), + 'canCDN' => true, )); } else { $e_file = pht('Required');