Page MenuHomePhabricator

D10054.id24538.diff
No OneTemporary

D10054.id24538.diff

diff --git a/resources/sql/autopatches/20140731.cancdn.php b/resources/sql/autopatches/20140731.cancdn.php
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20140731.cancdn.php
@@ -0,0 +1,20 @@
+<?php
+
+$table = new PhabricatorFile();
+$conn_w = $table->establishConnection('w');
+foreach (new LiskMigrationIterator($table) as $file) {
+ $id = $file->getID();
+ echo "Updating flags for file {$id}...\n";
+ $meta = $file->getMetadata();
+ if (!idx($meta, 'canCDN')) {
+
+ $meta['canCDN'] = true;
+
+ queryfx(
+ $conn_w,
+ 'UPDATE %T SET metadata = %s WHERE id = %d',
+ $table->getTableName(),
+ json_encode($meta),
+ $id);
+ }
+}
diff --git a/src/applications/files/application/PhabricatorFilesApplication.php b/src/applications/files/application/PhabricatorFilesApplication.php
--- a/src/applications/files/application/PhabricatorFilesApplication.php
+++ b/src/applications/files/application/PhabricatorFilesApplication.php
@@ -52,6 +52,8 @@
'delete/(?P<id>[1-9]\d*)/' => 'PhabricatorFileDeleteController',
'edit/(?P<id>[1-9]\d*)/' => 'PhabricatorFileEditController',
'info/(?P<phid>[^/]+)/' => 'PhabricatorFileInfoController',
+ 'data/(?P<key>[^/]+)/(?P<phid>[^/]+)/(?P<token>[^/]+)/.*'
+ => 'PhabricatorFileDataController',
'data/(?P<key>[^/]+)/(?P<phid>[^/]+)/.*'
=> 'PhabricatorFileDataController',
'proxy/' => 'PhabricatorFileProxyController',
diff --git a/src/applications/files/controller/PhabricatorFileDataController.php b/src/applications/files/controller/PhabricatorFileDataController.php
--- a/src/applications/files/controller/PhabricatorFileDataController.php
+++ b/src/applications/files/controller/PhabricatorFileDataController.php
@@ -4,47 +4,118 @@
private $phid;
private $key;
+ private $token;
public function willProcessRequest(array $data) {
$this->phid = $data['phid'];
$this->key = $data['key'];
+ $this->token = idx($data, 'token');
}
public function shouldRequireLogin() {
return false;
}
+ protected function checkFileAndToken($file) {
+ if (!$file) {
+ return new Aphront404Response();
+ }
+
+ if (!$file->validateSecretKey($this->key)) {
+ return new Aphront403Response();
+ }
+
+ return null;
+ }
+
public function processRequest() {
$request = $this->getRequest();
$alt = PhabricatorEnv::getEnvConfig('security.alternate-file-domain');
- $uri = new PhutilURI($alt);
- $alt_domain = $uri->getDomain();
- if ($alt_domain && ($alt_domain != $request->getHost())) {
+ $base_uri = PhabricatorEnv::getEnvConfig('phabricator.base-uri');
+ $alt_uri = new PhutilURI($alt);
+ $alt_domain = $alt_uri->getDomain();
+ $req_domain = $request->getHost();
+ $main_domain = id(new PhutilURI($base_uri))->getDomain();
+
+ $cache_response = true;
+
+ if (empty($alt) || $main_domain == $alt_domain) {
+ // Alternate files domain isn't configured or it's set
+ // to the same as the default domain
+
+ // load the file with permissions checks;
+ $file = id(new PhabricatorFileQuery())
+ ->setViewer($request->getUser())
+ ->withPHIDs(array($this->phid))
+ ->executeOne();
+
+ $error_response = $this->checkFileAndToken($file);
+ if ($error_response) {
+ return $error_response;
+ }
+
+ // when the file is not CDNable, don't allow cache
+ $cache_response = $file->getCanCDN();
+ } else if ($req_domain != $alt_domain) {
+ // Alternate domain is configured but this request isn't using it
+
+ // load the file with permissions checks;
+ $file = id(new PhabricatorFileQuery())
+ ->setViewer($request->getUser())
+ ->withPHIDs(array($this->phid))
+ ->executeOne();
+
+ $error_response = $this->checkFileAndToken($file);
+ if ($error_response) {
+ return $error_response;
+ }
+
+ // if the user can see the file, generate a token;
+ // redirect to the alt domain with the token;
return id(new AphrontRedirectResponse())
- ->setURI($uri->setPath($request->getPath()));
- }
+ ->setURI($file->getCDNURIWithToken());
- // NOTE: This endpoint will ideally be accessed via CDN or otherwise on
- // a non-credentialed domain. Knowing the file's secret key gives you
- // access, regardless of authentication on the request itself.
+ } else {
+ // We are using the alternate domain
- $file = id(new PhabricatorFileQuery())
- ->setViewer(PhabricatorUser::getOmnipotentUser())
- ->withPHIDs(array($this->phid))
- ->executeOne();
- if (!$file) {
- return new Aphront404Response();
- }
+ // load the file, bypassing permission checks;
+ $file = id(new PhabricatorFileQuery())
+ ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->withPHIDs(array($this->phid))
+ ->executeOne();
- if (!$file->validateSecretKey($this->key)) {
- return new Aphront403Response();
+ $error_response = $this->checkFileAndToken($file);
+ if ($error_response) {
+ return $error_response;
+ }
+
+ if ($this->token) {
+ // validate the token, if it is valid, continue
+ $validated_token = $file->validateOneTimeToken($this->token);
+
+ if (!$validated_token) {
+ return new Aphront403Response();
+ }
+ // return the file data without cache headers
+ $cache_response = false;
+ } else if (!$file->getCanCDN()) {
+ // file cannot be served via cdn, and no token given
+ // redirect to the main domain to aquire a token
+ $file_uri = id(new PhutilURI($file->getViewURI()))
+ ->setDomain($main_domain);
+
+ return id(new AphrontRedirectResponse())
+ ->setURI($file_uri);
+ }
}
$data = $file->loadFileData();
$response = new AphrontFileResponse();
$response->setContent($data);
- $response->setCacheDurationInSeconds(60 * 60 * 24 * 30);
+ if ($cache_response) {
+ $response->setCacheDurationInSeconds(60 * 60 * 24 * 30);
+ }
// NOTE: It's important to accept "Range" requests when playing audio.
// If we don't, Safari has difficulty figuring out how long sounds are
@@ -58,6 +129,9 @@
$response->setHTTPResponseCode(206);
$response->setRange((int)$matches[1], (int)$matches[2]);
}
+ } else if (isset($validated_token)) {
+ // consume the one-time token if we have one.
+ $validated_token->delete();
}
$is_viewable = $file->isViewableInBrowser();

File Metadata

Mime Type
text/plain
Expires
Wed, Mar 5, 3:16 AM (6 d, 23 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7223435
Default Alt Text
D10054.id24538.diff (6 KB)

Event Timeline