@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

authored by

Mukunda Modell and committed by
epriestley
12aaa942 c0585b7a

+75 -1
+1
scripts/util/add_macro.php
··· 52 52 $data, 53 53 array( 54 54 'name' => basename($path), 55 + 'canCDN' => true, 55 56 )); 56 57 57 58 $macro = id(new PhabricatorFileImageMacro())
+1
src/applications/auth/provider/PhabricatorAuthProvider.php
··· 243 243 $image_uri, 244 244 array( 245 245 'name' => $name, 246 + 'canCDN' => true 246 247 )); 247 248 unset($unguarded); 248 249
+5
src/applications/files/PhabricatorImageTransformer.php
··· 16 16 array( 17 17 'name' => 'meme-'.$file->getName(), 18 18 'ttl' => time() + 60 * 60 * 24, 19 + 'canCDN' => true, 19 20 )); 20 21 } 21 22 ··· 30 31 $image, 31 32 array( 32 33 'name' => 'thumb-'.$file->getName(), 34 + 'canCDN' => true, 33 35 )); 34 36 } 35 37 ··· 45 47 $image, 46 48 array( 47 49 'name' => 'profile-'.$file->getName(), 50 + 'canCDN' => true, 48 51 )); 49 52 } 50 53 ··· 58 61 $image, 59 62 array( 60 63 'name' => 'preview-'.$file->getName(), 64 + 'canCDN' => true, 61 65 )); 62 66 } 63 67 ··· 79 83 $image, 80 84 array( 81 85 'name' => 'conpherence-'.$file->getName(), 86 + 'canCDN' => true, 82 87 )); 83 88 } 84 89
+1
src/applications/files/controller/PhabricatorFileComposeController.php
··· 38 38 $data, 39 39 array( 40 40 'name' => 'project.png', 41 + 'canCDN' => true, 41 42 )); 42 43 43 44 $content = array(
+63 -1
src/applications/files/storage/PhabricatorFile.php
··· 7 7 PhabricatorFlaggableInterface, 8 8 PhabricatorPolicyInterface { 9 9 10 + const ONETIME_TEMPORARY_TOKEN_TYPE = 'file:onetime'; 10 11 const STORAGE_FORMAT_RAW = 'raw'; 11 12 12 13 const METADATA_IMAGE_WIDTH = 'width'; 13 14 const METADATA_IMAGE_HEIGHT = 'height'; 15 + const METADATA_CAN_CDN = 'cancdn'; 14 16 15 17 protected $name; 16 18 protected $mimeType; ··· 202 204 } 203 205 204 206 private static function buildFromFileData($data, array $params = array()) { 205 - $selector = PhabricatorEnv::newObjectFromConfig('storage.engine-selector'); 206 207 207 208 if (isset($params['storageEngines'])) { 208 209 $engines = $params['storageEngines']; ··· 268 269 269 270 if (idx($params, 'viewPolicy')) { 270 271 $file->setViewPolicy($params['viewPolicy']); 272 + } 273 + 274 + if (idx($params, 'canCDN')) { 275 + $file->setCanCDN(true); 271 276 } 272 277 273 278 $file->setStorageEngine($engine_identifier); ··· 851 856 } 852 857 return idx($this->metadata, self::METADATA_IMAGE_WIDTH); 853 858 } 859 + 860 + public function getCanCDN() { 861 + if (!$this->isViewableImage()) { 862 + return false; 863 + } 864 + return idx($this->metadata, self::METADATA_CAN_CDN); 865 + } 866 + 867 + public function setCanCDN($can_cdn) { 868 + $this->metadata[self::METADATA_CAN_CDN] = $can_cdn ? 1 : 0; 869 + return $this; 870 + } 871 + 872 + protected function generateOneTimeToken() { 873 + $key = Filesystem::readRandomCharacters(16); 874 + 875 + // Save the new secret. 876 + return id(new PhabricatorAuthTemporaryToken()) 877 + ->setObjectPHID($this->getPHID()) 878 + ->setTokenType(self::ONETIME_TEMPORARY_TOKEN_TYPE) 879 + ->setTokenExpires(time() + phutil_units('1 hour in seconds')) 880 + ->setTokenCode(PhabricatorHash::digest($key)) 881 + ->save(); 882 + } 883 + 884 + public function validateOneTimeToken($token_code) { 885 + $token = id(new PhabricatorAuthTemporaryTokenQuery()) 886 + ->setViewer(PhabricatorUser::getOmnipotentUser()) 887 + ->withObjectPHIDs(array($this->getPHID())) 888 + ->withTokenTypes(array(self::ONETIME_TEMPORARY_TOKEN_TYPE)) 889 + ->withExpired(false) 890 + ->withTokenCodes(array($token_code)) 891 + ->executeOne(); 892 + 893 + return $token; 894 + } 895 + 896 + /** Get the CDN uri for this file 897 + * This will generate a one-time-use token if 898 + * security.alternate_file_domain is set in the config. 899 + */ 900 + public function getCDNURIWithToken() { 901 + if (!$this->getPHID()) { 902 + throw new Exception( 903 + 'You must save a file before you can generate a CDN URI.'); 904 + } 905 + $name = phutil_escape_uri($this->getName()); 906 + 907 + $path = '/file/data' 908 + .'/'.$this->getSecretKey() 909 + .'/'.$this->getPHID() 910 + .'/'.$this->generateOneTimeToken() 911 + .'/'.$name; 912 + return PhabricatorEnv::getCDNURI($path); 913 + } 914 + 915 + 854 916 855 917 /** 856 918 * Write the policy edge between this file and some object.
+2
src/applications/macro/controller/PhabricatorMacroEditController.php
··· 64 64 'name' => $request->getStr('name'), 65 65 'authorPHID' => $user->getPHID(), 66 66 'isExplicitUpload' => true, 67 + 'canCDN' => true, 67 68 )); 68 69 } else if ($request->getStr('url')) { 69 70 try { ··· 73 74 'name' => $request->getStr('name'), 74 75 'authorPHID' => $user->getPHID(), 75 76 'isExplicitUpload' => true, 77 + 'canCDN' => true, 76 78 )); 77 79 } catch (Exception $ex) { 78 80 $errors[] = pht('Could not fetch URL: %s', $ex->getMessage());
+1
src/applications/people/controller/PhabricatorPeopleProfilePictureController.php
··· 53 53 $_FILES['picture'], 54 54 array( 55 55 'authorPHID' => $viewer->getPHID(), 56 + 'canCDN' => true, 56 57 )); 57 58 } else { 58 59 $e_file = pht('Required');
+1
src/applications/project/controller/PhabricatorProjectEditPictureController.php
··· 50 50 $_FILES['picture'], 51 51 array( 52 52 'authorPHID' => $viewer->getPHID(), 53 + 'canCDN' => true, 53 54 )); 54 55 } else { 55 56 $e_file = pht('Required');