-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SRI + XHTML #5742
base: master
Are you sure you want to change the base?
SRI + XHTML #5742
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -46,6 +46,7 @@ class rcmail_output_html extends rcmail_output | |
protected $body = ''; | ||
protected $base_path = ''; | ||
protected $assets_path; | ||
protected $assets_sri = false; | ||
protected $assets_dir = RCUBE_INSTALL_PATH; | ||
protected $devel_mode = false; | ||
|
||
|
@@ -84,6 +85,7 @@ public function __construct($task = null, $framed = false) | |
$this->set_env('skin', $skin); | ||
|
||
$this->set_assets_path($this->config->get('assets_path'), $this->config->get('assets_dir')); | ||
$this->assets_sri = $this->config->get('assets_sri'); | ||
|
||
if (!empty($_REQUEST['_extwin'])) | ||
$this->set_env('extwin', 1); | ||
|
@@ -755,6 +757,29 @@ public function raise_error($code, $message) | |
exit; | ||
} | ||
|
||
/** | ||
* Get the sha384 hash for local assets | ||
*/ | ||
public function asset_sri($path) | ||
{ | ||
// iframe content can't be in a different domain | ||
// @TODO: check if assests are on a different domain | ||
|
||
if (!$this->assets_sri || in_array($path[0], array('?', '/', '.')) || strpos($path, '://')) { | ||
return false; | ||
} | ||
|
||
list($file) = explode('?', $path, 2); | ||
if (!empty($file) && is_readable($file)) { | ||
$content = @file_get_contents($this->assets_dir . $file); | ||
if ($content !== false) { | ||
return 'sha384-'.base64_encode(hash('sha384', $content, true)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would be good to check if 'hash' function exists, e.g. when you set $this->assets_sri. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fair point. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I propose to use hash_file() instead of hash() and file_get_contents(). |
||
} | ||
} | ||
|
||
return false; | ||
} | ||
|
||
/** | ||
* Modify path by adding URL prefix if configured | ||
*/ | ||
|
@@ -802,7 +827,7 @@ protected function globals_callback($matches) | |
protected function fix_paths($output) | ||
{ | ||
return preg_replace_callback( | ||
'!(src|href|background)=(["\']?)([a-z0-9/_.-]+)(["\'\s>])!i', | ||
'!(src|href|background)=(["\']?)([a-z0-9/_.-]+)\2([\s>]?)!i', | ||
array($this, 'file_callback'), $output); | ||
} | ||
|
||
|
@@ -826,7 +851,34 @@ protected function file_callback($matches) | |
$file = $this->file_mod($file); | ||
} | ||
|
||
return $matches[1] . '=' . $matches[2] . $file . $matches[4]; | ||
return $matches[1] . '=' . $matches[2] . $file . $matches[2] . $matches[4]; | ||
} | ||
|
||
/** | ||
* Add SRI tags to assets | ||
*/ | ||
protected function include_assets_sri($output) | ||
{ | ||
return preg_replace_callback( | ||
'!(src|href|background)=(["\']?)([a-z0-9/_.?=-]+)\2([\s>])?!i', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. W3C specification talks only about link and script tags. Do we really want to handle all others, e.g. img? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I went this route because it was easier to implement for everything and because future browsers may support SRI in other tags. I concur that for performance reasons this might not be the best approach. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A slightly off-topic comment: the current way of implementing these features using templates (i.e., generate a document, then use regexes) seems error-prone and inefficient. I think a DOM-based (or similar) document generation approach could be more reliable and flexible (even though it's hard to say what the effect on performance may be.) Have you considered changing this? |
||
array($this, 'sri_callback'), $output); | ||
} | ||
|
||
/** | ||
* Callback function for preg_replace_callback in include_assets_sri() | ||
* | ||
* @return string Parsed string | ||
*/ | ||
protected function sri_callback($matches) | ||
{ | ||
$attrs = ''; | ||
$sri = $this->asset_sri($matches[3]); | ||
|
||
if (!empty($sri)) { | ||
$attrs = ' integrity="' . $sri . '" crossorigin="anonymous"'; | ||
} | ||
|
||
return $matches[1] . '=' . $matches[2] . $matches[3] . $matches[2] . $attrs . $matches[4]; | ||
} | ||
|
||
/** | ||
|
@@ -835,7 +887,7 @@ protected function file_callback($matches) | |
protected function fix_assets_paths($output) | ||
{ | ||
return preg_replace_callback( | ||
'!(src|href|background)=(["\']?)([a-z0-9/_.?=-]+)(["\'\s>])!i', | ||
'!(src|href|background)=(["\']?)([a-z0-9/_.?=-]+)\2([\s>])?!i', | ||
array($this, 'assets_callback'), $output); | ||
} | ||
|
||
|
@@ -848,7 +900,7 @@ protected function assets_callback($matches) | |
{ | ||
$file = $this->asset_url($matches[3]); | ||
|
||
return $matches[1] . '=' . $matches[2] . $file . $matches[4]; | ||
return $matches[1] . '=' . $matches[2] . $file . $matches[2] . $matches[4]; | ||
} | ||
|
||
/** | ||
|
@@ -1679,6 +1731,10 @@ protected function _write($templ = '', $base_path = '') | |
|
||
$output = $this->parse_with_globals($this->fix_paths($output)); | ||
|
||
if ($this->assets_sri) { | ||
$output = $this->include_assets_sri($output); | ||
} | ||
|
||
if ($this->assets_path) { | ||
$output = $this->fix_assets_paths($output); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here you use assets_dir, but one line above you don't.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair point. I missed that.