Codeigniter global_xss_filtering - codeigniter

In my codeigniter config I have $config['global_xss_filtering'] = TRUE;. In my admin section I have a ckeditor which generates the frontend content.
Everything that is typed and placed inside the editor works fine, images are displayed nice, html is working. All except flash. Whenever I switch to html mode and paste a youtube code piece it is escaped and the code is visible on the frontpage instead of showing a youtube movie.
If I set $config['global_xss_filtering'] = FALSE; the youtube code is passed like it should. This is because 'object', 'embed' etc are flagged as "naughty" by CI and thus escaped.
How can I bypass the xss filtering for this one controller method?

Turn it off by default then enable it for places that really need it.
For example, I have it turned off for all my controllers, then enable it for comments, pages, etc.
One thing you can do is create a MY_Input (or MY_Security in CI 2) like the one in PyroCMS and override the xss_clean method with an exact copy, minus the object|embed| part of the regex.
http://github.com/pyrocms/pyrocms/blob/master/system/pyrocms/libraries/MY_Security.php
It's one hell of a long way around, but it works.
Perhaps we could create a config option could be created listing the bad elements for 2.0?

My case was that I wanted global_xss_filtering to be on by default but sometimes I needed the $_POST (pst you can do this to any global php array e.g. $_GET...) data to be raw as send from the browser, so my solution was to:
open index.php in root folder of the project
added the following line of code $unsanitized_post = $_POST; after $application_folder = 'application'; (line #92)
then whenever I needed the raw $_POST I would do the following:
global $unsanitized_post;
print_r($unsanitized_post);

In CodeIgniter 2.0 the best thing to do is to override the xss_clean on the core CI library, using MY_Security.php put this on application/core folder then using /application/config.php
$config['xss_exclude_uris'] = array('controller/method');
here's the MY_Security.php https://gist.github.com/slick2/39f54a5310e29c5a8387:
<?php
/**
* CodeIgniter version 2
* Note: Put this on your application/core folder
*/
class MY_Security extends CI_Security {
/**
* Method: __construct();
* magic
*/
function __construct()
{
parent::__construct();
}
function xss_clean($str, $is_image = FALSE)
{
$bypass = FALSE;
/**
* By pass controllers set in /application/config/config.php
* config.php
* $config['xss_exclude_uris'] = array('controller/method')
*/
$config = new CI_Config;
$uri = new CI_URI;
$uri->_fetch_uri_string();
$uri->_explode_segments();
$controllers_list = $config->item('xss_exclude_uris');
// we need controller class and method only
if (!empty($controllers_list))
{
$segments = array(0 => NULL, 1 => NULL);
$segments = $uri->segment_array();
if (!empty($segments))
{
if (!empty($segments[1]))
{
$action = $segments[0] . '/' . $segments[1];
}
else
{
$action = $segments[0];
}
if (in_array($action, $controllers_list))
{
$bypass = TRUE;
}
}
// we unset the variable
unset($config);
unset($uri);
}
if ($bypass)
{
return $str;
}
else
{
return parent::xss_clean($str, $is_image);
}
}
}

Simple do the following on the views when displaying embedded object code like from YouTube and etc:
echo str_replace(array('<', '>'), array('<', '>'), $embed_filed);

The global XSS Filtering is only escaping (or converting) certain "dangerous" html tags like <html>
Simple Workaround:
Set $config['global_xss_filtering'] = TRUE;
Run your POST data through HTMLPurifier to remove any nasty <script> tags or javascript.
HTMLPurifier Docs
HTMLPurifier Codeigniter Integration
On the page where you receive the forms POST data use html_entity_decode() to undo what XSS filtering did.
//by decoding first, we remove everything that XSS filter did
//then we encode all characters equally.
$content = html_entity_decode($this->input->post('template_content'))
Then immediately run it through htmlentities()
$content = htmlentities($content);
Store as a Blob in MySQL database
When you want to display the
information to the user for editing run html_entity_decode()
This is how I did it. If anyone knows of a major flaw in what I did, please tell me. It seems to be working fine for me. Haven't had any unexpected errors.

Related

TYPO3: clear cache of a page when file metadata is changed

I have a custom plugin which shows files for download based on sys_category.
When an editor changes the meta data of a file, e.g. changes the title or category, the changes are only reflected in the frontend when the complete frontend cache is cleared.
I've tried to add this to page TSconfig:
[page|uid = 0]
TCEMAIN.clearCacheCmd = 17
[global]
But this doesn't work. Any other idea how to clear the cache, when a sys_file_metadata record is changed?
Here is my solution. Thx Aristeidis for the hint.
ext_localconf.php
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass']['my_extension_key'] =
\Vendor\ExtKey\Hooks\DataHandler::class;
Classes/Hooks/DataHandler.php
<?php
namespace Vendor\ExtKey\Hooks;
use TYPO3\CMS\Core\Cache\CacheManager;
use TYPO3\CMS\Core\Utility\GeneralUtility;
class DataHandler
{
public function processDatamap_afterDatabaseOperations(
$status,
$table,
$recordUid,
array $fields,
\TYPO3\CMS\Core\DataHandling\DataHandler $parentObject
) {
if ($table === 'sys_file_metadata') {
// hardcoded list of page uids to clear
$pageIdsToClear = [17];
if (!is_array($pageIdsToClear)) {
$pageIdsToClear = [(int)$pageIdsToClear];
}
$tags = array_map(function ($item) {
return 'pageId_' . $item;
}, $pageIdsToClear);
GeneralUtility::makeInstance(CacheManager::class)->flushCachesInGroupByTags('pages', $tags);
}
}
}
Of course this could be improved more:
Currently the list of page uids is hardcoded. That could be made configureable via extension manager settings.
A check could be implemented to only delete the cache if the file has a certain sys_category assigned, e.g. Downloads
But for the moment this solution is enough for my needs.

Front-End Plug-In Page

Ok, so I've looked at many posts on here about similar topics, but every single one of them is a rewrite rule for an actual php file in the url such as cart.php rather than the pretty permalink /cart/.
Basically, all I'm trying to do here is have WordPress include a template whenever a specific url is visited. In this case, example.com/cart/. Since this code is for a plug-in, it's a url that does not exist, and I cannot create a page for it. I'm trying to use a rewrite rule, along with query vars, to display the correct template when the user visits /cart/. I think I'm pretty close, but I've tried it several different ways, and I know I'm probably missing something obvious. I keep getting a 404 error, and I'm pretty sure it's my rewrite rule that is the problem. Can you guys give me a hand with this one?
Code:
/* Rewrite Rules */
add_action('init', 'llc_product_rewrite_rule');
function llc_product_rewrite_rule() {
add_rewrite_rule( 'cart/', 'index.php?llc_page=cart', 'top' );
}
/* Query Vars */
add_filter( 'query_vars', 'llc_product_register_query_var' );
function llc_product_register_query_var( $vars ) {
$vars[] = 'llc_page';
return $vars;
}
/* Parse Request */
add_action('parse_request', 'llc_cart_template');
function llc_cart_template() {
if (get_query_var('llc_page') && (get_query_var('llc_page') == "cart")) {
include plugin_dir_path(__FILE__).'inc/cart.php';
exit();
}
return;
}
Thank you for all of your well thought out responses you guys, but unfortunately I don't have all day and had to go through trial and error hell to figure this one out.
So firstly, if you want to simply have example.com/cart/ load a specific page template, when the page does not exist (for example if you need your wordpress plug-in to generate the page), this is how you'll need to set up your code. To clarify what's different from the code in my question, it's the rewrite rule, and the way I included the template. I used template_include rather than parse_request.
/* Rewrite Rules */
add_action('init', 'llc_product_rewrite_rule');
function llc_product_rewrite_rule() {
add_rewrite_rule( 'cart/?$', 'index.php?llc_page=cart', 'top' );
}
/* Query Vars */
add_filter( 'query_vars', 'llc_product_register_query_var' );
function llc_product_register_query_var( $vars ) {
$vars[] = 'llc_page';
return $vars;
}
/* Template Include */
add_filter('template_include', 'llc_cart_template_include', 1, 1);
function llc_cart_template_include($template)
{
global $wp_query;
$llc_page_value = $wp_query->query_vars['llc_page'];
if ($llc_page_value && $llc_page_value == "cart") {
return plugin_dir_path(__FILE__).'inc/cart.php';
}
return $template;
}

silverstripe static publisher - pages affected by DataObject Changes

is there a possibility to trigger an update of the cache if a DataObject is edited?
for example updating a News DataObject should update the cache of pages, that are displaying these NewsObjects.
many thanx,
Florian
Here is what I could do using the StaticPublishQueue module. In your NewsDataObject.php:
function onAfterWrite() {
parent::onAfterWrite();
$url = array();
$pages = $this->Pages(); //has_many link to pages that include this DataObject
foreach($pages as $page) {
$pagesAffected = $page->pagesAffected();
if ($pagesAffected && count($pagesAffected) > 0) {
$urls = array_merge((array)$urls, (array)$pagesAffected);
}
}
URLArrayObject::add_urls($urls);
}
This takes each of the pages that references your DataObject, asks it for all it's URL and the URL of any related pages (e.g. Virtual Pages that reference that page), compiles all the URLs into a big array, then adds that array to the static publishing queue. The queue will gradually process until all the affected pages are republished.
The event system allows you to add a layer of abstraction between the republishing and the triggers for republishing, but for something simple you don't necessarily need to use it. Instead, you can add pages to the queue directly. (You might also like to read this blog post describing the StaticPublishQueue module)
The StaticPublisherQueue module will handle that for you.
In case anyone else comes across this, and doesn't wish to use the StaticPublishQueue module instead of StaticPublisher, it does appear to be possible in StaticPublisher, the following works for me:
function onAfterWrite() {
parent::onAfterWrite();
$urls = array();
$pages = Page::get();
foreach($pages as $page) {
$urls[] = $page->Link();
}
$sp = new FilesystemPublisher();
$sp->publishPages($urls);
}
Note the last 2 lines, and use the Page::get to specify the exact pages that need to be updated.

How to override save() method in a component

Where and how I am overriding the save method in Joomla 3.0 custom component ?
Current situation:
Custom administrator component.
I have a list view that displays all people stored in table.
Clicking on one entry I get to the detailed view where a form is loaded and it's fields can be edited.
On save, the values are stored in the database. This all works fine.However, ....
When hitting save I wish to modify a field before storing it into the database. How do I override the save function and where? I have been searching this forum and googled quiet a bit to find ways to implement this. Anyone who give me a simple example or point me into the right direction ?
Thanks.
Just adding this for anyone who wants to know the answer to the question itself - this works if you explicitly wish to override the save function. However, look at the actual solution of how to manipulate values!
You override it in the controller, like this:
/**
* save a record (and redirect to main page)
* #return void
*/
function save()
{
$model = $this->getModel('hello');
if ($model->store()) {
$msg = JText::_( 'Greeting Saved!' );
} else {
$msg = JText::_( 'Error Saving Greeting' );
}
// Check the table in so it can be edited.... we are done with it anyway
$link = 'index.php?option=com_hello';
$this->setRedirect($link, $msg);
}
More details here: Joomla Docs - Adding Backend Actions
The prepareTable in the model (as mentioned above) is intended for that (prepare and sanitise the table prior to saving). In case you want to us the ID, though, you should consider using the postSaveHook in the controller:
protected function postSaveHook($model, $validData) {
$item = $model->getItem();
$itemid = $item->get('id');
}
The postSaveHook is called after save is done, thus allowing for newly inserted ID's to be used.
You can use the prepareTable function in the model file (administrator/components/yourComponent/models/yourComponent.php)
protected function prepareTable($table)
{
$table->fieldname = newvalue;
}

Passing variables before controller URI segment in CodeIgniter

I would like to pass some site-wide validated variables before controller segment in URL.
Example:
Default URL would be:
www.mysite.com/controller/method/variable/
Sometimes I'd like to have also URL like this to refer to user created sub-configuration of this site (theme, menus, ...), so user could share this site URL nicely and others would see the site though his custom configurations.
www.mysite.com/username/controller/method/variable
Here username is custom part of base_url. It should be validated against database and set as session variable to use it later in my controllers and change theme for example. Also all the links on the site would start to use www.mysite.com/username as base_url after website is entered with this username in the URL.
One way to solve this would be routing it like this:
controller/method/variable_name1/variable_value1/user_conf/username
...and the add the implementation to every single controller in my project. But this is not an elegant solution.
Is this what you're after:
$route['(:any)/(:any)'] = '$2/$1';
where all your function definitions have the username as the last parameter:
class Controller{function page(var1, var2, ..., varn, username){}}
Or, if you only want in on one specific page you could do something like this:
$route['(:any)/controller/page/(:any)'] = 'controller/page/$2/$1'; //This will work for the above class.
Or, if you want it for a number of functions in a controller you could do this:
$route['(:any)/controller/([func1|func2|funcn]+)/(:any)'] = 'controller/$2/$3/$1';
After messing with this problem for a day I ended up with adding custom router class to my project. I'm working in CodeIgniter 2.0, so the location of this file should be application/core/MY_Router.php
My code is following:
class MY_Router extends CI_Router {
// --------------------------------------------------------------------
/**
* OVERRIDE
*
* Validates the supplied segments. Attempts to determine the path to
* the controller.
*
* #access private
* #param array
* #return array
*/
function _validate_request($segments)
{
if (count($segments) == 0)
{
return $segments;
}
// Does the requested controller exist in the root folder?
if (file_exists(APPPATH.'controllers/'.$segments[0].EXT))
{
return $segments;
}
$users["username"] = 1;
$users["minu_pood"] = 2;
// $users[...] = ...;
// ...
// Basically here I load all the
// possbile username values from DB, memcache, filesystem, ...
if (isset($users[$segments[0]])) {
// If my segments[0] is in this set
// then do the session actions or add cookie in my cast.
setcookie('username_is', $segments[0], time() + (86400 * 7));
// After that remove this segment so
// rounter could search for controller!
array_shift($segments);
return $segments;
}
// So segments[0] was not a controller and also not a username...
// Nothing else to do at this point but show a 404
show_404($segments[0]);
}
}

Resources