1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-09-19 16:58:48 +02:00

Always serve "{meme ...}" from the CDN domain, never from the primary domain

Summary:
Ref T13101. This is a minimal change to make "{meme ...}" work with the new Content-Security-Policy by using an Ajax request to generate the image and then swapping the source on the client.

This could be much cleaner (see T5258, etc).

Test Plan: Used `{meme, src=cat6, above=i am, below=cat}`, chuckled completely unironically.

Maniphest Tasks: T13101

Differential Revision: https://secure.phabricator.com/D19196
This commit is contained in:
epriestley 2018-03-08 07:36:32 -08:00
parent 6095d88998
commit 98cac2cc29
3 changed files with 99 additions and 42 deletions

View file

@ -13,18 +13,25 @@ final class PhabricatorMacroMemeController
$lower_text = $request->getStr('lowertext');
$viewer = $request->getViewer();
$uri = self::generateMacro($viewer, $macro_name,
$upper_text, $lower_text);
if ($uri === false) {
return new Aphront404Response();
}
return id(new AphrontRedirectResponse())
->setIsExternal(true)
->setURI($uri);
$uri = self::generateMacro(
$viewer,
$macro_name,
$upper_text,
$lower_text);
$content = array(
'imageURI' => $uri,
);
return id(new AphrontAjaxResponse())->setContent($content);
}
public static function generateMacro($viewer, $macro_name, $upper_text,
$lower_text) {
public static function generateMacro(
PhabricatorUser $viewer,
$macro_name,
$upper_text,
$lower_text) {
$macro = id(new PhabricatorMacroQuery())
->setViewer($viewer)
->withNames(array($macro_name))
@ -35,34 +42,75 @@ final class PhabricatorMacroMemeController
}
$file = $macro->getFile();
$upper_text = strtoupper($upper_text);
$lower_text = strtoupper($lower_text);
$mixed_text = md5($upper_text).':'.md5($lower_text);
$hash = 'meme'.hash('sha256', $mixed_text);
$xform = id(new PhabricatorTransformedFile())
->loadOneWhere('originalphid=%s and transform=%s',
$file->getPHID(), $hash);
$upper_text = phutil_utf8_strtoupper($upper_text);
$lower_text = phutil_utf8_strtoupper($lower_text);
if ($xform) {
$memefile = id(new PhabricatorFileQuery())
->setViewer($viewer)
->withPHIDs(array($xform->getTransformedPHID()))
->executeOne();
if ($memefile) {
return $memefile->getBestURI();
}
$hash = PhabricatorHash::digestForIndex(
phutil_json_encode(
array(
'kind' => 'meme',
'upper' => $upper_text,
'lower' => $lower_text,
)));
$xfile = self::loadTransformedFile($viewer, $file->getPHID(), $hash);
if ($xfile) {
return $xfile->getViewURI();
}
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
$transformers = (new PhabricatorImageTransformer());
$newfile = $transformers
->executeMemeTransform($file, $upper_text, $lower_text);
$xfile = new PhabricatorTransformedFile();
$xfile->setOriginalPHID($file->getPHID());
$xfile->setTransformedPHID($newfile->getPHID());
$xfile->setTransform($hash);
$xfile->save();
$transformer = new PhabricatorImageTransformer();
return $newfile->getBestURI();
$new_file = $transformer->executeMemeTransform(
$file,
$upper_text,
$lower_text);
$xfile = id(new PhabricatorTransformedFile())
->setOriginalPHID($file->getPHID())
->setTransformedPHID($new_file->getPHID())
->setTransform($hash);
try {
$caught = null;
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
try {
$xfile->save();
} catch (Exception $ex) {
$caught = $ex;
}
unset($unguarded);
if ($caught) {
throw $caught;
}
return $new_file->getViewURI();
} catch (AphrontDuplicateKeyQueryException $ex) {
$xfile = self::loadTransformedFile($viewer, $file->getPHID(), $hash);
if (!$xfile) {
throw $ex;
}
return $xfile->getViewURI();
}
}
private static function loadTransformedFile(
PhabricatorUser $viewer,
$file_phid,
$hash) {
$xform = id(new PhabricatorTransformedFile())->loadOneWhere(
'originalPHID = %s AND transform = %s',
$file_phid,
$hash);
if (!$xform) {
return null;
}
return id(new PhabricatorFileQuery())
->setViewer($viewer)
->withPHIDs(array($xform->getTransformedPHID()))
->executeOne();
}
}

View file

@ -50,13 +50,10 @@ final class PhabricatorMemeRemarkupRule extends PhutilRemarkupRule {
$options['above'],
$options['below']);
$img = $this->newTag(
'img',
array(
'src' => $uri,
'alt' => $alt_text,
'class' => 'phabricator-remarkup-macro',
));
$img = id(new PHUIRemarkupImageView())
->setURI($uri)
->addClass('phabricator-remarkup-macro')
->setAlt($alt_text);
}
return $this->getEngine()->storeText($img);

View file

@ -7,6 +7,7 @@ final class PHUIRemarkupImageView
private $width;
private $height;
private $alt;
private $classes = array();
public function setURI($uri) {
$this->uri = $uri;
@ -44,6 +45,11 @@ final class PHUIRemarkupImageView
return $this->alt;
}
public function addClass($class) {
$this->classes[] = $class;
return $this;
}
public function render() {
$id = celerity_generate_unique_node_id();
@ -54,6 +60,11 @@ final class PHUIRemarkupImageView
'imageID' => $id,
));
$classes = null;
if ($this->classes) {
$classes = implode(' ', $this->classes);
}
return phutil_tag(
'img',
array(
@ -61,6 +72,7 @@ final class PHUIRemarkupImageView
'width' => $this->getWidth(),
'height' => $this->getHeight(),
'alt' => $this->getAlt(),
'class' => $classes,
));
}