2011-01-25 18:59:31 +01:00
|
|
|
<?php
|
|
|
|
|
2011-07-04 20:22:42 +02:00
|
|
|
/**
|
|
|
|
* Tracks and resolves dependencies the page declares with
|
|
|
|
* @{function:require_celerity_resource}, and then builds appropriate HTML or
|
|
|
|
* Ajax responses.
|
|
|
|
*/
|
2015-06-15 10:02:26 +02:00
|
|
|
final class CelerityStaticResourceResponse extends Phobject {
|
2011-01-25 18:59:31 +01:00
|
|
|
|
|
|
|
private $symbols = array();
|
|
|
|
private $needsResolve = true;
|
|
|
|
private $resolved;
|
2011-01-30 01:10:05 +01:00
|
|
|
private $packaged;
|
2011-01-25 20:57:47 +01:00
|
|
|
private $metadata = array();
|
|
|
|
private $metadataBlock = 0;
|
2016-06-20 20:49:11 +02:00
|
|
|
private $metadataLocked;
|
2011-01-25 20:57:47 +01:00
|
|
|
private $behaviors = array();
|
Bring Javelin into Phabricator via git submodule, not copy-and-paste
Summary:
Javelin is currently embedded in Phabricator via copy-and-paste of prebuilt
packages. This is not so great.
Pull it in as a submodule instead and make all the Phabriator resources declare
proper dependency trees. Add Javelin linting.
Test Plan:
I tried to run through pretty much all the JS functionality on the site. This is
still a high-risk change, but I did a pretty thorough test
Differential: inline comments, revealing diffs, list tokenizers, comment
preview, editing/deleting comments, add review action.
Maniphest: list tokenizer, comment actions
Herald: rule editing, tokenizers, add/remove rows
Reviewed By: tomo
Reviewers: aran, tomo, mroch, jungejason, tuomaspelkonen
CC: aran, tomo, epriestley
Differential Revision: 223
2011-05-04 00:11:55 +02:00
|
|
|
private $hasRendered = array();
|
2015-06-20 15:10:42 +02:00
|
|
|
private $postprocessorKey;
|
Emit a "Content-Security-Policy" HTTP header
Summary:
See PHI399. Ref T4340. This header provides an additional layer of protection against various attacks, including XSS attacks which embed inline `<script ...>` or `onhover="..."` content into the document.
**style-src**: The "unsafe-inline" directive affects both `style="..."` and `<style>`. We use a lot of `style="..."`, some very legitimately, so we can't realistically get away from this any time soon. We only use one `<style>` (for monospaced font preferences) but can't disable `<style>` without disabling `style="..."`.
**img-src**: We use "data:" URIs to inline small images into CSS, and there's a significant performance benefit from doing this. There doesn't seem to be a way to allow "data" URIs in CSS without allowing them in the document itself.
**script-src** and **frame-src**: For a small number of flows (Recaptcha, Stripe) we embed external javascript, some of which embeds child elements (or additional resources) into the document. We now whitelist these narrowly on the respective pages.
This won't work with Quicksand, so I've blacklisted it for now.
**connect-src**: We need to include `'self'` for AJAX to work, and any websocket URIs.
**Clickjacking**: We now have three layers of protection:
- X-Frame-Options: works in older browsers.
- `frame-ancestors 'none'`: does the same thing.
- Explicit framebust in JX.Stratcom after initialization: works in ancient IE.
We could probably drop the explicit framebust but it wasn't difficult to retain.
**script tags**: We previously used an inline `<script>` tag to start Javelin. I've moved this to `<data data-javelin-init ...>` tags, which seems to work properly.
**`__DEV__`**: We previously used an inline `<script>` tag to set the `__DEV__` mode flag. I tried using the "initialization" tags for this, but they fire too late. I moved it to `<html data-developer-mode="1">`, which seems OK everywhere.
**CSP Scope**: Only the CSP header on the original request appears to matter -- you can't refine the scope by emitting headers on CSS/JS. To reduce confusion, I disabled the headers on those response types. More headers could be disabled, although we're likely already deep in the land of diminishing returns.
**Initialization**: The initialization sequence has changed slightly. Previously, we waited for the <script> in bottom of the document to evaluate. Now, we go fishing for tags when domcontentready fires.
Test Plan:
- Browsed around in Firefox, Safari and Chrome looking for console warnings. Interacted with various Javascript behaviors. Enabled Quicksand.
- Disabled all the framebusting, launched a clickjacking attack, verified that each layer of protection is individually effective.
- Verified that the XHProf iframe in Darkconsole and the PHPAST frame layout work properly.
- Enabled notifications, verified no complaints about connecting to Aphlict.
- Hit `__DEV__` mode warnings based on the new data attribute.
- Tried to do sketchy stuff with `data:` URIs and SVGs. This works but doesn't seem to be able to do anything dangerous.
- Went through the Stripe and Recaptcha workflows.
- Dumped and examined the CSP headers with `curl`, etc.
- Added a raw <script> tag to a page (as though I'd found an XSS attack), verified it was no longer executed.
Maniphest Tasks: T4340
Differential Revision: https://secure.phabricator.com/D19143
2018-02-27 15:56:15 +01:00
|
|
|
private $contentSecurityPolicyURIs = array();
|
2011-01-25 20:57:47 +01:00
|
|
|
|
|
|
|
public function __construct() {
|
|
|
|
if (isset($_REQUEST['__metablock__'])) {
|
|
|
|
$this->metadataBlock = (int)$_REQUEST['__metablock__'];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public function addMetadata($metadata) {
|
2016-06-20 20:49:11 +02:00
|
|
|
if ($this->metadataLocked) {
|
|
|
|
throw new Exception(
|
|
|
|
pht(
|
|
|
|
'Attempting to add more metadata after metadata has been '.
|
|
|
|
'locked.'));
|
|
|
|
}
|
|
|
|
|
2011-01-25 20:57:47 +01:00
|
|
|
$id = count($this->metadata);
|
|
|
|
$this->metadata[$id] = $metadata;
|
|
|
|
return $this->metadataBlock.'_'.$id;
|
|
|
|
}
|
|
|
|
|
Emit a "Content-Security-Policy" HTTP header
Summary:
See PHI399. Ref T4340. This header provides an additional layer of protection against various attacks, including XSS attacks which embed inline `<script ...>` or `onhover="..."` content into the document.
**style-src**: The "unsafe-inline" directive affects both `style="..."` and `<style>`. We use a lot of `style="..."`, some very legitimately, so we can't realistically get away from this any time soon. We only use one `<style>` (for monospaced font preferences) but can't disable `<style>` without disabling `style="..."`.
**img-src**: We use "data:" URIs to inline small images into CSS, and there's a significant performance benefit from doing this. There doesn't seem to be a way to allow "data" URIs in CSS without allowing them in the document itself.
**script-src** and **frame-src**: For a small number of flows (Recaptcha, Stripe) we embed external javascript, some of which embeds child elements (or additional resources) into the document. We now whitelist these narrowly on the respective pages.
This won't work with Quicksand, so I've blacklisted it for now.
**connect-src**: We need to include `'self'` for AJAX to work, and any websocket URIs.
**Clickjacking**: We now have three layers of protection:
- X-Frame-Options: works in older browsers.
- `frame-ancestors 'none'`: does the same thing.
- Explicit framebust in JX.Stratcom after initialization: works in ancient IE.
We could probably drop the explicit framebust but it wasn't difficult to retain.
**script tags**: We previously used an inline `<script>` tag to start Javelin. I've moved this to `<data data-javelin-init ...>` tags, which seems to work properly.
**`__DEV__`**: We previously used an inline `<script>` tag to set the `__DEV__` mode flag. I tried using the "initialization" tags for this, but they fire too late. I moved it to `<html data-developer-mode="1">`, which seems OK everywhere.
**CSP Scope**: Only the CSP header on the original request appears to matter -- you can't refine the scope by emitting headers on CSS/JS. To reduce confusion, I disabled the headers on those response types. More headers could be disabled, although we're likely already deep in the land of diminishing returns.
**Initialization**: The initialization sequence has changed slightly. Previously, we waited for the <script> in bottom of the document to evaluate. Now, we go fishing for tags when domcontentready fires.
Test Plan:
- Browsed around in Firefox, Safari and Chrome looking for console warnings. Interacted with various Javascript behaviors. Enabled Quicksand.
- Disabled all the framebusting, launched a clickjacking attack, verified that each layer of protection is individually effective.
- Verified that the XHProf iframe in Darkconsole and the PHPAST frame layout work properly.
- Enabled notifications, verified no complaints about connecting to Aphlict.
- Hit `__DEV__` mode warnings based on the new data attribute.
- Tried to do sketchy stuff with `data:` URIs and SVGs. This works but doesn't seem to be able to do anything dangerous.
- Went through the Stripe and Recaptcha workflows.
- Dumped and examined the CSP headers with `curl`, etc.
- Added a raw <script> tag to a page (as though I'd found an XSS attack), verified it was no longer executed.
Maniphest Tasks: T4340
Differential Revision: https://secure.phabricator.com/D19143
2018-02-27 15:56:15 +01:00
|
|
|
public function addContentSecurityPolicyURI($kind, $uri) {
|
|
|
|
$this->contentSecurityPolicyURIs[$kind][] = $uri;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getContentSecurityPolicyURIMap() {
|
|
|
|
return $this->contentSecurityPolicyURIs;
|
|
|
|
}
|
|
|
|
|
2011-01-25 20:57:47 +01:00
|
|
|
public function getMetadataBlock() {
|
|
|
|
return $this->metadataBlock;
|
|
|
|
}
|
|
|
|
|
2015-06-20 15:10:42 +02:00
|
|
|
public function setPostprocessorKey($postprocessor_key) {
|
|
|
|
$this->postprocessorKey = $postprocessor_key;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getPostprocessorKey() {
|
|
|
|
return $this->postprocessorKey;
|
|
|
|
}
|
|
|
|
|
2011-05-31 19:23:31 +02:00
|
|
|
/**
|
2015-05-18 22:57:21 +02:00
|
|
|
* Register a behavior for initialization.
|
|
|
|
*
|
|
|
|
* NOTE: If `$config` is empty, a behavior will execute only once even if it
|
|
|
|
* is initialized multiple times. If `$config` is nonempty, the behavior will
|
|
|
|
* be invoked once for each configuration.
|
2011-05-31 19:23:31 +02:00
|
|
|
*/
|
2014-01-02 20:59:35 +01:00
|
|
|
public function initBehavior(
|
|
|
|
$behavior,
|
|
|
|
array $config = array(),
|
2015-05-18 22:57:21 +02:00
|
|
|
$source_name = null) {
|
2014-01-02 20:59:35 +01:00
|
|
|
|
|
|
|
$this->requireResource('javelin-behavior-'.$behavior, $source_name);
|
2011-05-31 19:23:31 +02:00
|
|
|
|
|
|
|
if (empty($this->behaviors[$behavior])) {
|
|
|
|
$this->behaviors[$behavior] = array();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($config) {
|
|
|
|
$this->behaviors[$behavior][] = $config;
|
|
|
|
}
|
|
|
|
|
2011-01-25 20:57:47 +01:00
|
|
|
return $this;
|
|
|
|
}
|
2011-01-25 18:59:31 +01:00
|
|
|
|
2014-01-02 20:59:35 +01:00
|
|
|
public function requireResource($symbol, $source_name) {
|
|
|
|
if (isset($this->symbols[$source_name][$symbol])) {
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify that the resource exists.
|
|
|
|
$map = CelerityResourceMap::getNamedInstance($source_name);
|
|
|
|
$name = $map->getResourceNameForSymbol($symbol);
|
|
|
|
if ($name === null) {
|
|
|
|
throw new Exception(
|
|
|
|
pht(
|
|
|
|
'No resource with symbol "%s" exists in source "%s"!',
|
|
|
|
$symbol,
|
|
|
|
$source_name));
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->symbols[$source_name][$symbol] = true;
|
2011-01-25 18:59:31 +01:00
|
|
|
$this->needsResolve = true;
|
2014-01-02 20:59:35 +01:00
|
|
|
|
2011-01-25 18:59:31 +01:00
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function resolveResources() {
|
|
|
|
if ($this->needsResolve) {
|
2014-01-02 20:59:35 +01:00
|
|
|
$this->packaged = array();
|
|
|
|
foreach ($this->symbols as $source_name => $symbols_map) {
|
|
|
|
$symbols = array_keys($symbols_map);
|
2014-01-01 03:03:24 +01:00
|
|
|
|
2014-01-02 20:59:35 +01:00
|
|
|
$map = CelerityResourceMap::getNamedInstance($source_name);
|
|
|
|
$packaged = $map->getPackagedNamesForSymbols($symbols);
|
2014-01-01 03:03:24 +01:00
|
|
|
|
2014-01-02 20:59:35 +01:00
|
|
|
$this->packaged[$source_name] = $packaged;
|
|
|
|
}
|
2011-01-25 18:59:31 +01:00
|
|
|
$this->needsResolve = false;
|
|
|
|
}
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2014-01-01 16:46:18 +01:00
|
|
|
public function renderSingleResource($symbol, $source_name) {
|
|
|
|
$map = CelerityResourceMap::getNamedInstance($source_name);
|
2014-01-01 03:03:24 +01:00
|
|
|
$packaged = $map->getPackagedNamesForSymbols(array($symbol));
|
2014-01-02 20:59:35 +01:00
|
|
|
return $this->renderPackagedResources($map, $packaged);
|
Bring Javelin into Phabricator via git submodule, not copy-and-paste
Summary:
Javelin is currently embedded in Phabricator via copy-and-paste of prebuilt
packages. This is not so great.
Pull it in as a submodule instead and make all the Phabriator resources declare
proper dependency trees. Add Javelin linting.
Test Plan:
I tried to run through pretty much all the JS functionality on the site. This is
still a high-risk change, but I did a pretty thorough test
Differential: inline comments, revealing diffs, list tokenizers, comment
preview, editing/deleting comments, add review action.
Maniphest: list tokenizer, comment actions
Herald: rule editing, tokenizers, add/remove rows
Reviewed By: tomo
Reviewers: aran, tomo, mroch, jungejason, tuomaspelkonen
CC: aran, tomo, epriestley
Differential Revision: 223
2011-05-04 00:11:55 +02:00
|
|
|
}
|
|
|
|
|
2011-01-25 18:59:31 +01:00
|
|
|
public function renderResourcesOfType($type) {
|
|
|
|
$this->resolveResources();
|
Bring Javelin into Phabricator via git submodule, not copy-and-paste
Summary:
Javelin is currently embedded in Phabricator via copy-and-paste of prebuilt
packages. This is not so great.
Pull it in as a submodule instead and make all the Phabriator resources declare
proper dependency trees. Add Javelin linting.
Test Plan:
I tried to run through pretty much all the JS functionality on the site. This is
still a high-risk change, but I did a pretty thorough test
Differential: inline comments, revealing diffs, list tokenizers, comment
preview, editing/deleting comments, add review action.
Maniphest: list tokenizer, comment actions
Herald: rule editing, tokenizers, add/remove rows
Reviewed By: tomo
Reviewers: aran, tomo, mroch, jungejason, tuomaspelkonen
CC: aran, tomo, epriestley
Differential Revision: 223
2011-05-04 00:11:55 +02:00
|
|
|
|
2014-01-02 20:59:35 +01:00
|
|
|
$result = array();
|
|
|
|
foreach ($this->packaged as $source_name => $resource_names) {
|
|
|
|
$map = CelerityResourceMap::getNamedInstance($source_name);
|
|
|
|
|
|
|
|
$resources_of_type = array();
|
|
|
|
foreach ($resource_names as $resource_name) {
|
|
|
|
$resource_type = $map->getResourceTypeForName($resource_name);
|
|
|
|
if ($resource_type == $type) {
|
|
|
|
$resources_of_type[] = $resource_name;
|
|
|
|
}
|
2011-01-25 18:59:31 +01:00
|
|
|
}
|
2014-01-02 20:59:35 +01:00
|
|
|
|
|
|
|
$result[] = $this->renderPackagedResources($map, $resources_of_type);
|
2011-01-25 18:59:31 +01:00
|
|
|
}
|
Bring Javelin into Phabricator via git submodule, not copy-and-paste
Summary:
Javelin is currently embedded in Phabricator via copy-and-paste of prebuilt
packages. This is not so great.
Pull it in as a submodule instead and make all the Phabriator resources declare
proper dependency trees. Add Javelin linting.
Test Plan:
I tried to run through pretty much all the JS functionality on the site. This is
still a high-risk change, but I did a pretty thorough test
Differential: inline comments, revealing diffs, list tokenizers, comment
preview, editing/deleting comments, add review action.
Maniphest: list tokenizer, comment actions
Herald: rule editing, tokenizers, add/remove rows
Reviewed By: tomo
Reviewers: aran, tomo, mroch, jungejason, tuomaspelkonen
CC: aran, tomo, epriestley
Differential Revision: 223
2011-05-04 00:11:55 +02:00
|
|
|
|
2014-01-02 20:59:35 +01:00
|
|
|
return phutil_implode_html('', $result);
|
Bring Javelin into Phabricator via git submodule, not copy-and-paste
Summary:
Javelin is currently embedded in Phabricator via copy-and-paste of prebuilt
packages. This is not so great.
Pull it in as a submodule instead and make all the Phabriator resources declare
proper dependency trees. Add Javelin linting.
Test Plan:
I tried to run through pretty much all the JS functionality on the site. This is
still a high-risk change, but I did a pretty thorough test
Differential: inline comments, revealing diffs, list tokenizers, comment
preview, editing/deleting comments, add review action.
Maniphest: list tokenizer, comment actions
Herald: rule editing, tokenizers, add/remove rows
Reviewed By: tomo
Reviewers: aran, tomo, mroch, jungejason, tuomaspelkonen
CC: aran, tomo, epriestley
Differential Revision: 223
2011-05-04 00:11:55 +02:00
|
|
|
}
|
|
|
|
|
2014-01-02 20:59:35 +01:00
|
|
|
private function renderPackagedResources(
|
|
|
|
CelerityResourceMap $map,
|
|
|
|
array $resources) {
|
|
|
|
|
Bring Javelin into Phabricator via git submodule, not copy-and-paste
Summary:
Javelin is currently embedded in Phabricator via copy-and-paste of prebuilt
packages. This is not so great.
Pull it in as a submodule instead and make all the Phabriator resources declare
proper dependency trees. Add Javelin linting.
Test Plan:
I tried to run through pretty much all the JS functionality on the site. This is
still a high-risk change, but I did a pretty thorough test
Differential: inline comments, revealing diffs, list tokenizers, comment
preview, editing/deleting comments, add review action.
Maniphest: list tokenizer, comment actions
Herald: rule editing, tokenizers, add/remove rows
Reviewed By: tomo
Reviewers: aran, tomo, mroch, jungejason, tuomaspelkonen
CC: aran, tomo, epriestley
Differential Revision: 223
2011-05-04 00:11:55 +02:00
|
|
|
$output = array();
|
2014-01-01 03:03:24 +01:00
|
|
|
foreach ($resources as $name) {
|
|
|
|
if (isset($this->hasRendered[$name])) {
|
Bring Javelin into Phabricator via git submodule, not copy-and-paste
Summary:
Javelin is currently embedded in Phabricator via copy-and-paste of prebuilt
packages. This is not so great.
Pull it in as a submodule instead and make all the Phabriator resources declare
proper dependency trees. Add Javelin linting.
Test Plan:
I tried to run through pretty much all the JS functionality on the site. This is
still a high-risk change, but I did a pretty thorough test
Differential: inline comments, revealing diffs, list tokenizers, comment
preview, editing/deleting comments, add review action.
Maniphest: list tokenizer, comment actions
Herald: rule editing, tokenizers, add/remove rows
Reviewed By: tomo
Reviewers: aran, tomo, mroch, jungejason, tuomaspelkonen
CC: aran, tomo, epriestley
Differential Revision: 223
2011-05-04 00:11:55 +02:00
|
|
|
continue;
|
|
|
|
}
|
2014-01-01 03:03:24 +01:00
|
|
|
$this->hasRendered[$name] = true;
|
Bring Javelin into Phabricator via git submodule, not copy-and-paste
Summary:
Javelin is currently embedded in Phabricator via copy-and-paste of prebuilt
packages. This is not so great.
Pull it in as a submodule instead and make all the Phabriator resources declare
proper dependency trees. Add Javelin linting.
Test Plan:
I tried to run through pretty much all the JS functionality on the site. This is
still a high-risk change, but I did a pretty thorough test
Differential: inline comments, revealing diffs, list tokenizers, comment
preview, editing/deleting comments, add review action.
Maniphest: list tokenizer, comment actions
Herald: rule editing, tokenizers, add/remove rows
Reviewed By: tomo
Reviewers: aran, tomo, mroch, jungejason, tuomaspelkonen
CC: aran, tomo, epriestley
Differential Revision: 223
2011-05-04 00:11:55 +02:00
|
|
|
|
2014-01-02 20:59:35 +01:00
|
|
|
$output[] = $this->renderResource($map, $name);
|
Bring Javelin into Phabricator via git submodule, not copy-and-paste
Summary:
Javelin is currently embedded in Phabricator via copy-and-paste of prebuilt
packages. This is not so great.
Pull it in as a submodule instead and make all the Phabriator resources declare
proper dependency trees. Add Javelin linting.
Test Plan:
I tried to run through pretty much all the JS functionality on the site. This is
still a high-risk change, but I did a pretty thorough test
Differential: inline comments, revealing diffs, list tokenizers, comment
preview, editing/deleting comments, add review action.
Maniphest: list tokenizer, comment actions
Herald: rule editing, tokenizers, add/remove rows
Reviewed By: tomo
Reviewers: aran, tomo, mroch, jungejason, tuomaspelkonen
CC: aran, tomo, epriestley
Differential Revision: 223
2011-05-04 00:11:55 +02:00
|
|
|
}
|
2014-01-02 20:59:35 +01:00
|
|
|
|
|
|
|
return $output;
|
2011-01-25 18:59:31 +01:00
|
|
|
}
|
|
|
|
|
2014-01-02 20:59:35 +01:00
|
|
|
private function renderResource(
|
|
|
|
CelerityResourceMap $map,
|
|
|
|
$name) {
|
|
|
|
|
|
|
|
$uri = $this->getURI($map, $name);
|
|
|
|
$type = $map->getResourceTypeForName($name);
|
|
|
|
|
2015-05-04 18:15:15 +02:00
|
|
|
$multimeter = MultimeterControl::getInstance();
|
|
|
|
if ($multimeter) {
|
|
|
|
$event_type = MultimeterEvent::TYPE_STATIC_RESOURCE;
|
|
|
|
$multimeter->newEvent($event_type, 'rsrc.'.$name, 1);
|
|
|
|
}
|
Skeleton for "Multimeter", a performance sampling application
Summary:
Ref T6930. This application collects and displays performance samples -- roughly, things Phabricator spent some kind of resource on. It will collect samples on different types of resources and events:
- Wall time (queries, service calls, pages)
- Bytes In / Bytes Out (requests)
- Implicit requests to CSS/JS (static resources)
I've started with the simplest case (static resources), since this can be used in an immediate, straghtforward way to improve packaging (look at which individual files have the most requests recently).
There's no aggregation yet and a lot of the data isn't collected properly. Future diffs will add more dimension data (controllers, users), more event and resource types (queries, service calls, wall time), and more display options (aggregation, sorting).
Test Plan: {F389344}
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley
Maniphest Tasks: T6930
Differential Revision: https://secure.phabricator.com/D12623
2015-05-01 22:19:43 +02:00
|
|
|
|
2014-01-01 03:03:24 +01:00
|
|
|
switch ($type) {
|
2011-01-25 18:59:31 +01:00
|
|
|
case 'css':
|
2013-01-18 03:39:02 +01:00
|
|
|
return phutil_tag(
|
2012-10-16 18:44:53 +02:00
|
|
|
'link',
|
|
|
|
array(
|
|
|
|
'rel' => 'stylesheet',
|
|
|
|
'type' => 'text/css',
|
|
|
|
'href' => $uri,
|
|
|
|
));
|
2011-01-25 18:59:31 +01:00
|
|
|
case 'js':
|
2013-01-18 03:57:09 +01:00
|
|
|
return phutil_tag(
|
2012-10-16 18:44:53 +02:00
|
|
|
'script',
|
|
|
|
array(
|
|
|
|
'type' => 'text/javascript',
|
|
|
|
'src' => $uri,
|
|
|
|
),
|
|
|
|
'');
|
2011-01-25 18:59:31 +01:00
|
|
|
}
|
2014-01-02 20:59:35 +01:00
|
|
|
|
|
|
|
throw new Exception(
|
|
|
|
pht(
|
|
|
|
'Unable to render resource "%s", which has unknown type "%s".',
|
|
|
|
$name,
|
|
|
|
$type));
|
2011-01-25 18:59:31 +01:00
|
|
|
}
|
|
|
|
|
Emit a "Content-Security-Policy" HTTP header
Summary:
See PHI399. Ref T4340. This header provides an additional layer of protection against various attacks, including XSS attacks which embed inline `<script ...>` or `onhover="..."` content into the document.
**style-src**: The "unsafe-inline" directive affects both `style="..."` and `<style>`. We use a lot of `style="..."`, some very legitimately, so we can't realistically get away from this any time soon. We only use one `<style>` (for monospaced font preferences) but can't disable `<style>` without disabling `style="..."`.
**img-src**: We use "data:" URIs to inline small images into CSS, and there's a significant performance benefit from doing this. There doesn't seem to be a way to allow "data" URIs in CSS without allowing them in the document itself.
**script-src** and **frame-src**: For a small number of flows (Recaptcha, Stripe) we embed external javascript, some of which embeds child elements (or additional resources) into the document. We now whitelist these narrowly on the respective pages.
This won't work with Quicksand, so I've blacklisted it for now.
**connect-src**: We need to include `'self'` for AJAX to work, and any websocket URIs.
**Clickjacking**: We now have three layers of protection:
- X-Frame-Options: works in older browsers.
- `frame-ancestors 'none'`: does the same thing.
- Explicit framebust in JX.Stratcom after initialization: works in ancient IE.
We could probably drop the explicit framebust but it wasn't difficult to retain.
**script tags**: We previously used an inline `<script>` tag to start Javelin. I've moved this to `<data data-javelin-init ...>` tags, which seems to work properly.
**`__DEV__`**: We previously used an inline `<script>` tag to set the `__DEV__` mode flag. I tried using the "initialization" tags for this, but they fire too late. I moved it to `<html data-developer-mode="1">`, which seems OK everywhere.
**CSP Scope**: Only the CSP header on the original request appears to matter -- you can't refine the scope by emitting headers on CSS/JS. To reduce confusion, I disabled the headers on those response types. More headers could be disabled, although we're likely already deep in the land of diminishing returns.
**Initialization**: The initialization sequence has changed slightly. Previously, we waited for the <script> in bottom of the document to evaluate. Now, we go fishing for tags when domcontentready fires.
Test Plan:
- Browsed around in Firefox, Safari and Chrome looking for console warnings. Interacted with various Javascript behaviors. Enabled Quicksand.
- Disabled all the framebusting, launched a clickjacking attack, verified that each layer of protection is individually effective.
- Verified that the XHProf iframe in Darkconsole and the PHPAST frame layout work properly.
- Enabled notifications, verified no complaints about connecting to Aphlict.
- Hit `__DEV__` mode warnings based on the new data attribute.
- Tried to do sketchy stuff with `data:` URIs and SVGs. This works but doesn't seem to be able to do anything dangerous.
- Went through the Stripe and Recaptcha workflows.
- Dumped and examined the CSP headers with `curl`, etc.
- Added a raw <script> tag to a page (as though I'd found an XSS attack), verified it was no longer executed.
Maniphest Tasks: T4340
Differential Revision: https://secure.phabricator.com/D19143
2018-02-27 15:56:15 +01:00
|
|
|
public function renderHTMLFooter($is_frameable) {
|
2016-06-20 20:49:11 +02:00
|
|
|
$this->metadataLocked = true;
|
|
|
|
|
Emit a "Content-Security-Policy" HTTP header
Summary:
See PHI399. Ref T4340. This header provides an additional layer of protection against various attacks, including XSS attacks which embed inline `<script ...>` or `onhover="..."` content into the document.
**style-src**: The "unsafe-inline" directive affects both `style="..."` and `<style>`. We use a lot of `style="..."`, some very legitimately, so we can't realistically get away from this any time soon. We only use one `<style>` (for monospaced font preferences) but can't disable `<style>` without disabling `style="..."`.
**img-src**: We use "data:" URIs to inline small images into CSS, and there's a significant performance benefit from doing this. There doesn't seem to be a way to allow "data" URIs in CSS without allowing them in the document itself.
**script-src** and **frame-src**: For a small number of flows (Recaptcha, Stripe) we embed external javascript, some of which embeds child elements (or additional resources) into the document. We now whitelist these narrowly on the respective pages.
This won't work with Quicksand, so I've blacklisted it for now.
**connect-src**: We need to include `'self'` for AJAX to work, and any websocket URIs.
**Clickjacking**: We now have three layers of protection:
- X-Frame-Options: works in older browsers.
- `frame-ancestors 'none'`: does the same thing.
- Explicit framebust in JX.Stratcom after initialization: works in ancient IE.
We could probably drop the explicit framebust but it wasn't difficult to retain.
**script tags**: We previously used an inline `<script>` tag to start Javelin. I've moved this to `<data data-javelin-init ...>` tags, which seems to work properly.
**`__DEV__`**: We previously used an inline `<script>` tag to set the `__DEV__` mode flag. I tried using the "initialization" tags for this, but they fire too late. I moved it to `<html data-developer-mode="1">`, which seems OK everywhere.
**CSP Scope**: Only the CSP header on the original request appears to matter -- you can't refine the scope by emitting headers on CSS/JS. To reduce confusion, I disabled the headers on those response types. More headers could be disabled, although we're likely already deep in the land of diminishing returns.
**Initialization**: The initialization sequence has changed slightly. Previously, we waited for the <script> in bottom of the document to evaluate. Now, we go fishing for tags when domcontentready fires.
Test Plan:
- Browsed around in Firefox, Safari and Chrome looking for console warnings. Interacted with various Javascript behaviors. Enabled Quicksand.
- Disabled all the framebusting, launched a clickjacking attack, verified that each layer of protection is individually effective.
- Verified that the XHProf iframe in Darkconsole and the PHPAST frame layout work properly.
- Enabled notifications, verified no complaints about connecting to Aphlict.
- Hit `__DEV__` mode warnings based on the new data attribute.
- Tried to do sketchy stuff with `data:` URIs and SVGs. This works but doesn't seem to be able to do anything dangerous.
- Went through the Stripe and Recaptcha workflows.
- Dumped and examined the CSP headers with `curl`, etc.
- Added a raw <script> tag to a page (as though I'd found an XSS attack), verified it was no longer executed.
Maniphest Tasks: T4340
Differential Revision: https://secure.phabricator.com/D19143
2018-02-27 15:56:15 +01:00
|
|
|
$merge_data = array(
|
|
|
|
'block' => $this->metadataBlock,
|
|
|
|
'data' => $this->metadata,
|
|
|
|
);
|
|
|
|
$this->metadata = array();
|
2011-01-25 20:57:47 +01:00
|
|
|
|
Emit a "Content-Security-Policy" HTTP header
Summary:
See PHI399. Ref T4340. This header provides an additional layer of protection against various attacks, including XSS attacks which embed inline `<script ...>` or `onhover="..."` content into the document.
**style-src**: The "unsafe-inline" directive affects both `style="..."` and `<style>`. We use a lot of `style="..."`, some very legitimately, so we can't realistically get away from this any time soon. We only use one `<style>` (for monospaced font preferences) but can't disable `<style>` without disabling `style="..."`.
**img-src**: We use "data:" URIs to inline small images into CSS, and there's a significant performance benefit from doing this. There doesn't seem to be a way to allow "data" URIs in CSS without allowing them in the document itself.
**script-src** and **frame-src**: For a small number of flows (Recaptcha, Stripe) we embed external javascript, some of which embeds child elements (or additional resources) into the document. We now whitelist these narrowly on the respective pages.
This won't work with Quicksand, so I've blacklisted it for now.
**connect-src**: We need to include `'self'` for AJAX to work, and any websocket URIs.
**Clickjacking**: We now have three layers of protection:
- X-Frame-Options: works in older browsers.
- `frame-ancestors 'none'`: does the same thing.
- Explicit framebust in JX.Stratcom after initialization: works in ancient IE.
We could probably drop the explicit framebust but it wasn't difficult to retain.
**script tags**: We previously used an inline `<script>` tag to start Javelin. I've moved this to `<data data-javelin-init ...>` tags, which seems to work properly.
**`__DEV__`**: We previously used an inline `<script>` tag to set the `__DEV__` mode flag. I tried using the "initialization" tags for this, but they fire too late. I moved it to `<html data-developer-mode="1">`, which seems OK everywhere.
**CSP Scope**: Only the CSP header on the original request appears to matter -- you can't refine the scope by emitting headers on CSS/JS. To reduce confusion, I disabled the headers on those response types. More headers could be disabled, although we're likely already deep in the land of diminishing returns.
**Initialization**: The initialization sequence has changed slightly. Previously, we waited for the <script> in bottom of the document to evaluate. Now, we go fishing for tags when domcontentready fires.
Test Plan:
- Browsed around in Firefox, Safari and Chrome looking for console warnings. Interacted with various Javascript behaviors. Enabled Quicksand.
- Disabled all the framebusting, launched a clickjacking attack, verified that each layer of protection is individually effective.
- Verified that the XHProf iframe in Darkconsole and the PHPAST frame layout work properly.
- Enabled notifications, verified no complaints about connecting to Aphlict.
- Hit `__DEV__` mode warnings based on the new data attribute.
- Tried to do sketchy stuff with `data:` URIs and SVGs. This works but doesn't seem to be able to do anything dangerous.
- Went through the Stripe and Recaptcha workflows.
- Dumped and examined the CSP headers with `curl`, etc.
- Added a raw <script> tag to a page (as though I'd found an XSS attack), verified it was no longer executed.
Maniphest Tasks: T4340
Differential Revision: https://secure.phabricator.com/D19143
2018-02-27 15:56:15 +01:00
|
|
|
$behavior_lists = array();
|
2011-01-25 20:57:47 +01:00
|
|
|
if ($this->behaviors) {
|
2011-12-07 22:49:56 +01:00
|
|
|
$behaviors = $this->behaviors;
|
2011-01-25 20:57:47 +01:00
|
|
|
$this->behaviors = array();
|
2011-12-07 22:49:56 +01:00
|
|
|
|
|
|
|
$higher_priority_names = array(
|
|
|
|
'refresh-csrf',
|
2011-12-23 02:59:00 +01:00
|
|
|
'aphront-basic-tokenizer',
|
2013-02-09 22:29:47 +01:00
|
|
|
'dark-console',
|
2013-03-01 03:58:00 +01:00
|
|
|
'history-install',
|
2011-12-07 22:49:56 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
$higher_priority_behaviors = array_select_keys(
|
|
|
|
$behaviors,
|
|
|
|
$higher_priority_names);
|
|
|
|
|
|
|
|
foreach ($higher_priority_names as $name) {
|
|
|
|
unset($behaviors[$name]);
|
|
|
|
}
|
|
|
|
|
|
|
|
$behavior_groups = array(
|
|
|
|
$higher_priority_behaviors,
|
2014-10-07 15:01:04 +02:00
|
|
|
$behaviors,
|
|
|
|
);
|
2011-12-07 22:49:56 +01:00
|
|
|
|
|
|
|
foreach ($behavior_groups as $group) {
|
|
|
|
if (!$group) {
|
|
|
|
continue;
|
|
|
|
}
|
Emit a "Content-Security-Policy" HTTP header
Summary:
See PHI399. Ref T4340. This header provides an additional layer of protection against various attacks, including XSS attacks which embed inline `<script ...>` or `onhover="..."` content into the document.
**style-src**: The "unsafe-inline" directive affects both `style="..."` and `<style>`. We use a lot of `style="..."`, some very legitimately, so we can't realistically get away from this any time soon. We only use one `<style>` (for monospaced font preferences) but can't disable `<style>` without disabling `style="..."`.
**img-src**: We use "data:" URIs to inline small images into CSS, and there's a significant performance benefit from doing this. There doesn't seem to be a way to allow "data" URIs in CSS without allowing them in the document itself.
**script-src** and **frame-src**: For a small number of flows (Recaptcha, Stripe) we embed external javascript, some of which embeds child elements (or additional resources) into the document. We now whitelist these narrowly on the respective pages.
This won't work with Quicksand, so I've blacklisted it for now.
**connect-src**: We need to include `'self'` for AJAX to work, and any websocket URIs.
**Clickjacking**: We now have three layers of protection:
- X-Frame-Options: works in older browsers.
- `frame-ancestors 'none'`: does the same thing.
- Explicit framebust in JX.Stratcom after initialization: works in ancient IE.
We could probably drop the explicit framebust but it wasn't difficult to retain.
**script tags**: We previously used an inline `<script>` tag to start Javelin. I've moved this to `<data data-javelin-init ...>` tags, which seems to work properly.
**`__DEV__`**: We previously used an inline `<script>` tag to set the `__DEV__` mode flag. I tried using the "initialization" tags for this, but they fire too late. I moved it to `<html data-developer-mode="1">`, which seems OK everywhere.
**CSP Scope**: Only the CSP header on the original request appears to matter -- you can't refine the scope by emitting headers on CSS/JS. To reduce confusion, I disabled the headers on those response types. More headers could be disabled, although we're likely already deep in the land of diminishing returns.
**Initialization**: The initialization sequence has changed slightly. Previously, we waited for the <script> in bottom of the document to evaluate. Now, we go fishing for tags when domcontentready fires.
Test Plan:
- Browsed around in Firefox, Safari and Chrome looking for console warnings. Interacted with various Javascript behaviors. Enabled Quicksand.
- Disabled all the framebusting, launched a clickjacking attack, verified that each layer of protection is individually effective.
- Verified that the XHProf iframe in Darkconsole and the PHPAST frame layout work properly.
- Enabled notifications, verified no complaints about connecting to Aphlict.
- Hit `__DEV__` mode warnings based on the new data attribute.
- Tried to do sketchy stuff with `data:` URIs and SVGs. This works but doesn't seem to be able to do anything dangerous.
- Went through the Stripe and Recaptcha workflows.
- Dumped and examined the CSP headers with `curl`, etc.
- Added a raw <script> tag to a page (as though I'd found an XSS attack), verified it was no longer executed.
Maniphest Tasks: T4340
Differential Revision: https://secure.phabricator.com/D19143
2018-02-27 15:56:15 +01:00
|
|
|
$behavior_lists[] = $group;
|
2011-12-07 22:49:56 +01:00
|
|
|
}
|
2011-01-25 20:57:47 +01:00
|
|
|
}
|
|
|
|
|
Emit a "Content-Security-Policy" HTTP header
Summary:
See PHI399. Ref T4340. This header provides an additional layer of protection against various attacks, including XSS attacks which embed inline `<script ...>` or `onhover="..."` content into the document.
**style-src**: The "unsafe-inline" directive affects both `style="..."` and `<style>`. We use a lot of `style="..."`, some very legitimately, so we can't realistically get away from this any time soon. We only use one `<style>` (for monospaced font preferences) but can't disable `<style>` without disabling `style="..."`.
**img-src**: We use "data:" URIs to inline small images into CSS, and there's a significant performance benefit from doing this. There doesn't seem to be a way to allow "data" URIs in CSS without allowing them in the document itself.
**script-src** and **frame-src**: For a small number of flows (Recaptcha, Stripe) we embed external javascript, some of which embeds child elements (or additional resources) into the document. We now whitelist these narrowly on the respective pages.
This won't work with Quicksand, so I've blacklisted it for now.
**connect-src**: We need to include `'self'` for AJAX to work, and any websocket URIs.
**Clickjacking**: We now have three layers of protection:
- X-Frame-Options: works in older browsers.
- `frame-ancestors 'none'`: does the same thing.
- Explicit framebust in JX.Stratcom after initialization: works in ancient IE.
We could probably drop the explicit framebust but it wasn't difficult to retain.
**script tags**: We previously used an inline `<script>` tag to start Javelin. I've moved this to `<data data-javelin-init ...>` tags, which seems to work properly.
**`__DEV__`**: We previously used an inline `<script>` tag to set the `__DEV__` mode flag. I tried using the "initialization" tags for this, but they fire too late. I moved it to `<html data-developer-mode="1">`, which seems OK everywhere.
**CSP Scope**: Only the CSP header on the original request appears to matter -- you can't refine the scope by emitting headers on CSS/JS. To reduce confusion, I disabled the headers on those response types. More headers could be disabled, although we're likely already deep in the land of diminishing returns.
**Initialization**: The initialization sequence has changed slightly. Previously, we waited for the <script> in bottom of the document to evaluate. Now, we go fishing for tags when domcontentready fires.
Test Plan:
- Browsed around in Firefox, Safari and Chrome looking for console warnings. Interacted with various Javascript behaviors. Enabled Quicksand.
- Disabled all the framebusting, launched a clickjacking attack, verified that each layer of protection is individually effective.
- Verified that the XHProf iframe in Darkconsole and the PHPAST frame layout work properly.
- Enabled notifications, verified no complaints about connecting to Aphlict.
- Hit `__DEV__` mode warnings based on the new data attribute.
- Tried to do sketchy stuff with `data:` URIs and SVGs. This works but doesn't seem to be able to do anything dangerous.
- Went through the Stripe and Recaptcha workflows.
- Dumped and examined the CSP headers with `curl`, etc.
- Added a raw <script> tag to a page (as though I'd found an XSS attack), verified it was no longer executed.
Maniphest Tasks: T4340
Differential Revision: https://secure.phabricator.com/D19143
2018-02-27 15:56:15 +01:00
|
|
|
$initializers = array();
|
|
|
|
|
|
|
|
// Even if there is no metadata on the page, Javelin uses the mergeData()
|
|
|
|
// call to start dispatching the event queue, so we always want to include
|
|
|
|
// this initializer.
|
|
|
|
$initializers[] = array(
|
|
|
|
'kind' => 'merge',
|
|
|
|
'data' => $merge_data,
|
|
|
|
);
|
|
|
|
|
|
|
|
foreach ($behavior_lists as $behavior_list) {
|
|
|
|
$initializers[] = array(
|
|
|
|
'kind' => 'behaviors',
|
|
|
|
'data' => $behavior_list,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($is_frameable) {
|
|
|
|
$initializers[] = array(
|
|
|
|
'data' => 'frameable',
|
|
|
|
'kind' => (bool)$is_frameable,
|
|
|
|
);
|
2011-01-25 20:57:47 +01:00
|
|
|
}
|
|
|
|
|
Emit a "Content-Security-Policy" HTTP header
Summary:
See PHI399. Ref T4340. This header provides an additional layer of protection against various attacks, including XSS attacks which embed inline `<script ...>` or `onhover="..."` content into the document.
**style-src**: The "unsafe-inline" directive affects both `style="..."` and `<style>`. We use a lot of `style="..."`, some very legitimately, so we can't realistically get away from this any time soon. We only use one `<style>` (for monospaced font preferences) but can't disable `<style>` without disabling `style="..."`.
**img-src**: We use "data:" URIs to inline small images into CSS, and there's a significant performance benefit from doing this. There doesn't seem to be a way to allow "data" URIs in CSS without allowing them in the document itself.
**script-src** and **frame-src**: For a small number of flows (Recaptcha, Stripe) we embed external javascript, some of which embeds child elements (or additional resources) into the document. We now whitelist these narrowly on the respective pages.
This won't work with Quicksand, so I've blacklisted it for now.
**connect-src**: We need to include `'self'` for AJAX to work, and any websocket URIs.
**Clickjacking**: We now have three layers of protection:
- X-Frame-Options: works in older browsers.
- `frame-ancestors 'none'`: does the same thing.
- Explicit framebust in JX.Stratcom after initialization: works in ancient IE.
We could probably drop the explicit framebust but it wasn't difficult to retain.
**script tags**: We previously used an inline `<script>` tag to start Javelin. I've moved this to `<data data-javelin-init ...>` tags, which seems to work properly.
**`__DEV__`**: We previously used an inline `<script>` tag to set the `__DEV__` mode flag. I tried using the "initialization" tags for this, but they fire too late. I moved it to `<html data-developer-mode="1">`, which seems OK everywhere.
**CSP Scope**: Only the CSP header on the original request appears to matter -- you can't refine the scope by emitting headers on CSS/JS. To reduce confusion, I disabled the headers on those response types. More headers could be disabled, although we're likely already deep in the land of diminishing returns.
**Initialization**: The initialization sequence has changed slightly. Previously, we waited for the <script> in bottom of the document to evaluate. Now, we go fishing for tags when domcontentready fires.
Test Plan:
- Browsed around in Firefox, Safari and Chrome looking for console warnings. Interacted with various Javascript behaviors. Enabled Quicksand.
- Disabled all the framebusting, launched a clickjacking attack, verified that each layer of protection is individually effective.
- Verified that the XHProf iframe in Darkconsole and the PHPAST frame layout work properly.
- Enabled notifications, verified no complaints about connecting to Aphlict.
- Hit `__DEV__` mode warnings based on the new data attribute.
- Tried to do sketchy stuff with `data:` URIs and SVGs. This works but doesn't seem to be able to do anything dangerous.
- Went through the Stripe and Recaptcha workflows.
- Dumped and examined the CSP headers with `curl`, etc.
- Added a raw <script> tag to a page (as though I'd found an XSS attack), verified it was no longer executed.
Maniphest Tasks: T4340
Differential Revision: https://secure.phabricator.com/D19143
2018-02-27 15:56:15 +01:00
|
|
|
$tags = array();
|
|
|
|
foreach ($initializers as $initializer) {
|
|
|
|
$data = $initializer['data'];
|
|
|
|
if (is_array($data)) {
|
|
|
|
$json_data = AphrontResponse::encodeJSONForHTTPResponse($data);
|
|
|
|
} else {
|
|
|
|
$json_data = json_encode($data);
|
|
|
|
}
|
|
|
|
|
|
|
|
$tags[] = phutil_tag(
|
|
|
|
'data',
|
|
|
|
array(
|
|
|
|
'data-javelin-init-kind' => $initializer['kind'],
|
|
|
|
'data-javelin-init-data' => $json_data,
|
|
|
|
));
|
2011-01-25 20:57:47 +01:00
|
|
|
}
|
Emit a "Content-Security-Policy" HTTP header
Summary:
See PHI399. Ref T4340. This header provides an additional layer of protection against various attacks, including XSS attacks which embed inline `<script ...>` or `onhover="..."` content into the document.
**style-src**: The "unsafe-inline" directive affects both `style="..."` and `<style>`. We use a lot of `style="..."`, some very legitimately, so we can't realistically get away from this any time soon. We only use one `<style>` (for monospaced font preferences) but can't disable `<style>` without disabling `style="..."`.
**img-src**: We use "data:" URIs to inline small images into CSS, and there's a significant performance benefit from doing this. There doesn't seem to be a way to allow "data" URIs in CSS without allowing them in the document itself.
**script-src** and **frame-src**: For a small number of flows (Recaptcha, Stripe) we embed external javascript, some of which embeds child elements (or additional resources) into the document. We now whitelist these narrowly on the respective pages.
This won't work with Quicksand, so I've blacklisted it for now.
**connect-src**: We need to include `'self'` for AJAX to work, and any websocket URIs.
**Clickjacking**: We now have three layers of protection:
- X-Frame-Options: works in older browsers.
- `frame-ancestors 'none'`: does the same thing.
- Explicit framebust in JX.Stratcom after initialization: works in ancient IE.
We could probably drop the explicit framebust but it wasn't difficult to retain.
**script tags**: We previously used an inline `<script>` tag to start Javelin. I've moved this to `<data data-javelin-init ...>` tags, which seems to work properly.
**`__DEV__`**: We previously used an inline `<script>` tag to set the `__DEV__` mode flag. I tried using the "initialization" tags for this, but they fire too late. I moved it to `<html data-developer-mode="1">`, which seems OK everywhere.
**CSP Scope**: Only the CSP header on the original request appears to matter -- you can't refine the scope by emitting headers on CSS/JS. To reduce confusion, I disabled the headers on those response types. More headers could be disabled, although we're likely already deep in the land of diminishing returns.
**Initialization**: The initialization sequence has changed slightly. Previously, we waited for the <script> in bottom of the document to evaluate. Now, we go fishing for tags when domcontentready fires.
Test Plan:
- Browsed around in Firefox, Safari and Chrome looking for console warnings. Interacted with various Javascript behaviors. Enabled Quicksand.
- Disabled all the framebusting, launched a clickjacking attack, verified that each layer of protection is individually effective.
- Verified that the XHProf iframe in Darkconsole and the PHPAST frame layout work properly.
- Enabled notifications, verified no complaints about connecting to Aphlict.
- Hit `__DEV__` mode warnings based on the new data attribute.
- Tried to do sketchy stuff with `data:` URIs and SVGs. This works but doesn't seem to be able to do anything dangerous.
- Went through the Stripe and Recaptcha workflows.
- Dumped and examined the CSP headers with `curl`, etc.
- Added a raw <script> tag to a page (as though I'd found an XSS attack), verified it was no longer executed.
Maniphest Tasks: T4340
Differential Revision: https://secure.phabricator.com/D19143
2018-02-27 15:56:15 +01:00
|
|
|
|
|
|
|
return $tags;
|
2011-01-25 20:57:47 +01:00
|
|
|
}
|
|
|
|
|
2013-04-21 02:55:47 +02:00
|
|
|
public static function renderInlineScript($data) {
|
|
|
|
if (stripos($data, '</script>') !== false) {
|
|
|
|
throw new Exception(
|
2015-05-22 09:27:56 +02:00
|
|
|
pht(
|
|
|
|
'Literal %s is not allowed inside inline script.',
|
|
|
|
'</script>'));
|
2013-04-21 02:55:47 +02:00
|
|
|
}
|
2013-10-16 18:28:37 +02:00
|
|
|
if (strpos($data, '<!') !== false) {
|
2015-05-22 09:27:56 +02:00
|
|
|
throw new Exception(
|
|
|
|
pht(
|
|
|
|
'Literal %s is not allowed inside inline script.',
|
|
|
|
'<!'));
|
2013-10-16 18:28:37 +02:00
|
|
|
}
|
2013-11-09 19:48:19 +01:00
|
|
|
// We don't use <![CDATA[ ]]> because it is ignored by HTML parsers. We
|
|
|
|
// would need to send the document with XHTML content type.
|
|
|
|
return phutil_tag(
|
|
|
|
'script',
|
|
|
|
array('type' => 'text/javascript'),
|
2013-04-21 02:55:47 +02:00
|
|
|
phutil_safe_html($data));
|
|
|
|
}
|
|
|
|
|
2012-02-14 23:51:51 +01:00
|
|
|
public function buildAjaxResponse($payload, $error = null) {
|
2011-01-25 20:57:47 +01:00
|
|
|
$response = array(
|
|
|
|
'error' => $error,
|
|
|
|
'payload' => $payload,
|
|
|
|
);
|
|
|
|
|
|
|
|
if ($this->metadata) {
|
|
|
|
$response['javelin_metadata'] = $this->metadata;
|
|
|
|
$this->metadata = array();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($this->behaviors) {
|
|
|
|
$response['javelin_behaviors'] = $this->behaviors;
|
|
|
|
$this->behaviors = array();
|
|
|
|
}
|
|
|
|
|
2012-11-21 17:37:01 +01:00
|
|
|
$this->resolveResources();
|
|
|
|
$resources = array();
|
2014-01-02 20:59:35 +01:00
|
|
|
foreach ($this->packaged as $source_name => $resource_names) {
|
|
|
|
$map = CelerityResourceMap::getNamedInstance($source_name);
|
|
|
|
foreach ($resource_names as $resource_name) {
|
|
|
|
$resources[] = $this->getURI($map, $resource_name);
|
|
|
|
}
|
2012-11-21 17:37:01 +01:00
|
|
|
}
|
|
|
|
if ($resources) {
|
|
|
|
$response['javelin_resources'] = $resources;
|
|
|
|
}
|
|
|
|
|
2011-01-25 20:57:47 +01:00
|
|
|
return $response;
|
|
|
|
}
|
|
|
|
|
2014-06-07 23:04:52 +02:00
|
|
|
public function getURI(
|
2014-01-02 20:59:35 +01:00
|
|
|
CelerityResourceMap $map,
|
2014-06-13 14:47:06 +02:00
|
|
|
$name,
|
|
|
|
$use_primary_domain = false) {
|
2014-01-02 20:59:35 +01:00
|
|
|
|
2014-01-01 03:03:24 +01:00
|
|
|
$uri = $map->getURIForName($name);
|
Add timestamps to development-mode static resource URIs
Summary:
When a developer changes CSS, it is normally sufficient to reload the page to get changes to show up, because browsers revalidate resources on reload.
However, if you reload the page and then an Ajax request adds new CSS to the page, this CSS does not trigger revalidation. The developer must currently clear their cache or re-run `scripts/celerity_mapper.php webroot`, to get this request to skip cache. We rarely use CSS over Ajax right now, so this hasn't cropped up much, but Conpherence does use this and clearing the resource is a big pain.
This seems to work fine normally, but I'm worried it might break some of the extra-celerity-resources stuff Facebook is doing.
Test Plan: In development mode, changed `conpherence/message-pane.css` and saw changes reflected on reload. Verified normal page loads do not cause additional HTTP requests. This change has no effect in production mode.
Reviewers: edward, vrana, btrahan
Reviewed By: vrana
CC: aran
Maniphest Tasks: T2428
Differential Revision: https://secure.phabricator.com/D4902
2013-02-11 20:06:41 +01:00
|
|
|
|
2015-06-20 15:10:42 +02:00
|
|
|
// If we have a postprocessor selected, add it to the URI.
|
|
|
|
$postprocessor_key = $this->getPostprocessorKey();
|
|
|
|
if ($postprocessor_key) {
|
|
|
|
$uri = preg_replace('@^/res/@', '/res/'.$postprocessor_key.'X/', $uri);
|
|
|
|
}
|
|
|
|
|
Add timestamps to development-mode static resource URIs
Summary:
When a developer changes CSS, it is normally sufficient to reload the page to get changes to show up, because browsers revalidate resources on reload.
However, if you reload the page and then an Ajax request adds new CSS to the page, this CSS does not trigger revalidation. The developer must currently clear their cache or re-run `scripts/celerity_mapper.php webroot`, to get this request to skip cache. We rarely use CSS over Ajax right now, so this hasn't cropped up much, but Conpherence does use this and clearing the resource is a big pain.
This seems to work fine normally, but I'm worried it might break some of the extra-celerity-resources stuff Facebook is doing.
Test Plan: In development mode, changed `conpherence/message-pane.css` and saw changes reflected on reload. Verified normal page loads do not cause additional HTTP requests. This change has no effect in production mode.
Reviewers: edward, vrana, btrahan
Reviewed By: vrana
CC: aran
Maniphest Tasks: T2428
Differential Revision: https://secure.phabricator.com/D4902
2013-02-11 20:06:41 +01:00
|
|
|
// In developer mode, we dump file modification times into the URI. When a
|
|
|
|
// page is reloaded in the browser, any resources brought in by Ajax calls
|
|
|
|
// do not trigger revalidation, so without this it's very difficult to get
|
|
|
|
// changes to Ajaxed-in CSS to work (you must clear your cache or rerun
|
|
|
|
// the map script). In production, we can assume the map script gets run
|
|
|
|
// after changes, and safely skip this.
|
|
|
|
if (PhabricatorEnv::getEnvConfig('phabricator.developer-mode')) {
|
2014-01-01 03:03:24 +01:00
|
|
|
$mtime = $map->getModifiedTimeForName($name);
|
Add timestamps to development-mode static resource URIs
Summary:
When a developer changes CSS, it is normally sufficient to reload the page to get changes to show up, because browsers revalidate resources on reload.
However, if you reload the page and then an Ajax request adds new CSS to the page, this CSS does not trigger revalidation. The developer must currently clear their cache or re-run `scripts/celerity_mapper.php webroot`, to get this request to skip cache. We rarely use CSS over Ajax right now, so this hasn't cropped up much, but Conpherence does use this and clearing the resource is a big pain.
This seems to work fine normally, but I'm worried it might break some of the extra-celerity-resources stuff Facebook is doing.
Test Plan: In development mode, changed `conpherence/message-pane.css` and saw changes reflected on reload. Verified normal page loads do not cause additional HTTP requests. This change has no effect in production mode.
Reviewers: edward, vrana, btrahan
Reviewed By: vrana
CC: aran
Maniphest Tasks: T2428
Differential Revision: https://secure.phabricator.com/D4902
2013-02-11 20:06:41 +01:00
|
|
|
$uri = preg_replace('@^/res/@', '/res/'.$mtime.'T/', $uri);
|
|
|
|
}
|
|
|
|
|
2014-06-13 14:47:06 +02:00
|
|
|
if ($use_primary_domain) {
|
|
|
|
return PhabricatorEnv::getURI($uri);
|
|
|
|
} else {
|
|
|
|
return PhabricatorEnv::getCDNURI($uri);
|
|
|
|
}
|
Add timestamps to development-mode static resource URIs
Summary:
When a developer changes CSS, it is normally sufficient to reload the page to get changes to show up, because browsers revalidate resources on reload.
However, if you reload the page and then an Ajax request adds new CSS to the page, this CSS does not trigger revalidation. The developer must currently clear their cache or re-run `scripts/celerity_mapper.php webroot`, to get this request to skip cache. We rarely use CSS over Ajax right now, so this hasn't cropped up much, but Conpherence does use this and clearing the resource is a big pain.
This seems to work fine normally, but I'm worried it might break some of the extra-celerity-resources stuff Facebook is doing.
Test Plan: In development mode, changed `conpherence/message-pane.css` and saw changes reflected on reload. Verified normal page loads do not cause additional HTTP requests. This change has no effect in production mode.
Reviewers: edward, vrana, btrahan
Reviewed By: vrana
CC: aran
Maniphest Tasks: T2428
Differential Revision: https://secure.phabricator.com/D4902
2013-02-11 20:06:41 +01:00
|
|
|
}
|
|
|
|
|
2011-01-25 18:59:31 +01:00
|
|
|
}
|