We have a Sitefinity 11.0.6701.0 site in which I have a page that contains a Content Block with an iframe in it. The page we are displaying in the iframe is dynamic and has a form in it - we are not concerned with clickjacking or anything like that as we host the src page as well.
We recently upgraded our site from version 8 and now the iframe's content (which we also host on a separate site) does not allow for the dynamic content to work.
I noticed that Sitefinity seems to be adding a sandbox="allow-scripts allow-same-origin" attribute to the iframe at runtime. I have attempted to change this to sandbox="allow-forms" as well as simply removing the sandbox attribute altogether, but Sitefinity dynamically adds the first attribute back in a runtime. It replace the "allow-forms" with the "allow-scripts allow-same-origin" attribute.
Does anyone know where this is controlled in Sitefinity and how we can overcome this problem? We need this page to be dynamic. For contractual reasons, I can't change actual code in our Sitefinity environment, only work within the CMS.
Thanks in advance,
Jamie
This is caused by the Html Sanitizer.
One option is to disable it under
Administration > Settings > Advanced > Security > Disable HTML sanitization
and restart the site.
Another option is to try and modify the sanitizer configuration as shown here:
https://docs.sitefinity.com/html-sanitization#modify-the-html-sanitizer-configuration
But looking at the decompiled code of v.11 it may not be that easy:
private class GanssHtmlSanitizer : HtmlSanitizer
{
private const string IframeNodeName = "iframe";
public GanssHtmlSanitizer() : base(null, null, null, null, null)
{
base.AllowedTags.Add("iframe");
base.PostProcessNode += new EventHandler<PostProcessNodeEventArgs>(this.GanssHtmlSanitizer_PostProcessNode);
}
private void GanssHtmlSanitizer_PostProcessNode(object sender, PostProcessNodeEventArgs e)
{
if (string.Compare(e.Node.NodeName, "iframe", true) == 0)
{
(e.Node as IElement).SetAttribute("sandbox", "allow-scripts allow-same-origin");
string attribute = (e.Node as IElement).GetAttribute("src");
(e.Node as IElement).SetAttribute("src", this.SanitizeUrl(attribute));
}
}
/// <inheritdoc />
public string SanitizeUrl(string url)
{
return base.SanitizeUrl(url, null);
}
}
Related
I am writing a module for Orchard CMS 1.8.1
I would like to add custom styles to all content parts that I have written for the module. I need these to work regardless of the theme chosen by the website admins. I could add links to the CSS and JS files in every view file for every content part - but that seems messy and prone to future bugs - what's the best way to have a single file that loads up the styles needed for all my content parts?
Should I provide a different Content.cshtml that includes the links? This also seems like it could be problematic if the admins need their own control over the main Content.cshtml
Many thanks
Handler should do the trick, I wrote this from the top of my head so not sure if it really works.
First create ResourceManifest.cs and define your stylesheets and scripts
public class ResourceManifest : IResourceManifestProvider
{
public void BuildManifests(ResourceManifestBuilder builder)
{
var manifest = builder.Add();
manifest.DefineStyle("MyStylesheet").SetUrl("mystylesheet.min.css", "mystylesheet.css").SetVersion("1.0.0");
manifest.DefineScript("MyScript").SetUrl("myscript.min.js", "myscript.js").SetVersion("1.0.0");
}
}
Then it should be enough to create content handler and override the BuildDisplayShape
public class MyResourceHandler : ContentHandler
{
private readonly Work<IResourceManager> _resourceManager;
public MyResourceHandler(Work<IResourceManager> resourceManager)
{
_resourceManager = resourceManager;
}
protected override void BuildDisplayShape(BuildDisplayContext context)
{
if (context.DisplayType == "Detail" && context.ContentItem.Has(typeof(MyPart)))
{
this._resourceManager.Value.Require("stylesheet", "MyStylesheet");
this._resourceManager.Value.Require("script", "MyScript");
}
base.BuildDisplayShape(context);
}
}
Adjust the IF as necessary. And let me know if it works ;)
Beauty of using ResourceManifest with versioning is that anyone can replace your stylesheets/javascript with their own just by defining style in their own ResourceManifest (module/theme) with same name and higher version number and don't have to touch any original files.
Summary
I'm having style issues when flipping master pages via a button event in asp.net 4.0. The new master switches, but the css from the old master remains. I don't understand how this could happen as the styles are defined within the head of the old master, and i can clearly see via the markup the new master is being displayed with whats supposed to be a totally different set of styles. Also, viewing source shows all the new css declarations in the head. How can i get this to "refresh" or "reload"?
Some details
I'm implementing a mobile version of my asp.net site. If a mobile device is detected i set a cookie and switch the master page in the preinit to a mobile friendly one. This works fine:
protected virtual void Page_PreInit(Object sender, EventArgs e)
{
if (IsMobile)
this.Page.MasterPageFile = "m-" + this.Page.MasterPageFile;
}
I have a "full site" button at the bottom that allows you to flip back and forth between the mobile and desktop view. When clicking it, i change the value in the cookie. Then when the page redirects to itself, the value is checked, and it gives the respective masterpage. This also "works", i can tell the right masterpage is rendering via markup. Except the styles from the mobile version remain even when the desktop master is being displayed. I did the redirect thinking it would prevent this.
// desktop/mobile site toggle button click event
protected void viewMobileButton_Click(Object sender, EventArgs e)
{
HttpCookie isMobileCookie = Cookies.snatchCookie("isMobile");
if (bool.Parse(isMobileCookie.Value))
Cookies.bakeCookie("isMobile", "false");
else
Cookies.bakeCookie("isMobile", "true");
Response.Redirect(Request.RawUrl);
}
This is the first time I've done anything like this, and not sure if i'm even going about it the right way, or how to debug from here. Thanks in advance for any help.
Edit
Ok, so i figured out it's related to the JQuery Mobile Scripts. JQuery Mobile has this way of tying pages together. I don't fully understand it, i think they use it for page transitions, and it's preventing my new CSS from registering. When i turn it off, my masterpage flips fine with css included. I'm looking into a way to turn off JQuery Mobile before my redirect. Note sure how though yet.
The problem ended up being related to JQuery Mobile AJAX for page-transitions. JQuery Mobile does not load the head of the document on additional page requests after the first.
So when i'd switch the mobile master to the desktop master, the head of the document wouldn't load to bring in my styles. There are a few way's this can be fixed:
This way just turns off AJAX altogether, and fixes the problem, but then you can't benefit from it:
<form data-ajax="false">
This is a way to do it problematically, but remind you, it will not work via an event after initialization of JQuery Mobile, so again you can't benefit from it:
$.mobile.ajaxEnabled = false;
The above two solutions i support could work if you redirected through a page first if you have to use an onclick event and an event handler.
A better solution is to add rel="external" to the link to tell JQM it's and outgoing link.
<a href="myself.com?mobile=true" rel="external" >
But because i couldn't run some code i wanted to in order to change the cookie, i had to pass a query string parameter, check it on the preinit, then set the cookie which my page also looks at on the preinit and flips the master.
Here's my full solution below in case someone is out there doing the exact same thing. Note because my website is using aliasing, i had to read Request.RawUrl and parse it myself since the Request.QueryString object did not contain the values i passed.
// reusable function that parses a string in standard query string format(foo=bar&dave=awesome) into a Dictionary collection of key/value pairs
// return the reference to the object, you have to assign it to a local un-instantiated name
// will accept a full url, or just a query string
protected Dictionary<string, string> parseQueryString(string url)
{
Dictionary<string, string> d = new Dictionary<string, string>();
if (!string.IsNullOrEmpty(url))
{
// if the string is still a full url vs just the query string
if (url.Contains("?"))
{
string[] urlArray = url.Split('?');
url = urlArray[1]; // snip the non query string business away
}
string[] paramArray = url.Split('&');
foreach (string param in paramArray)
{
if (param.Contains("="))
{
int index = param.IndexOf('=');
d.Add(param.Substring(0, index), param.Substring(++index));
}
}
}
return d;
}
Then i just use my dictionary object to evaluate and rebuild my url with the opposite mobile value, dynamically setting the href on the toggle link. Some code is obviosuly left out, but for perspective, base._iPage.QueryStringParams hold my dictionary object that was returned, and base._iPage.IsMobile is just a bool property i also have via the page interface i use, that all my pages, and user controls, ect, can talk to.
// get the left side fo the url, without querystrings
StringBuilder url = new StringBuilder(Request.RawUrl.Split('?')[0]);
// build link to self, preserving query strings, except flipping mobile value
if (base._iPage.QueryStringParams.Count != 0)
{
if (base._iPage.QueryStringParams.ContainsKey("mobile"))
{
// set to opposite of current
base._iPage.QueryStringParams["mobile"] = (!base._iPage.IsMobile).ToString();
}
int count = 0;
url.Append('?');
// loop through query string params, and add them back on
foreach (KeyValuePair<string, string> item in base._iPage.QueryStringParams)
{
count++;
url.Append(item.Key + "=" + item.Value + (count == base._iPage.QueryStringParams.Count ? "" : "&" ));
}
}
// assign rebuild url to href of toggle link
viewMobileButton.HRef = url.ToString();
}
Then on my pageinit this is where i actually check, first the quesry string, then the cookie, if neither of those are present, i run my mobile detection method, and set a cookie, and my interface bool property for easy access to conditionals that depends on it.
QueryStringParams = base.parseQueryString(Request.RawUrl);
if (QueryStringParams.ContainsKey("mobile") ? QueryStringParams["mobile"].ToLower().Equals("true") : false)
{
Cookies.bakeCookie("isMobile", "true"); // create a cookie
IsMobile = true;
}
else if (QueryStringParams.ContainsKey("mobile") ? QueryStringParams["mobile"].ToLower().Equals("false") : false)
{
Cookies.bakeCookie("isMobile", "false"); // create a cookie
IsMobile = false;
}
else
{
IsMobile = base.mobileDetection();
}
if (IsMobile)
this.Page.MasterPageFile = "m-" + this.Page.MasterPageFile;
}
Ok I have a TabNavigator component that keeps added a hash (#) to the URL. I need to prevent this. I have it set to historyManagementEnabled="false" but it is still adding the # to the URL when it initializes.
The reason why adding this hash is such a problem is because, I am using .htaccess to give my URL a pretty URL like domain.com/designer/category/product/id when the page is really located at domain.com/product.php?pid=id So in order for my assets to load correctly I had to add a base tag like this:
<base href="http://www.MYDOMAIN.com/" />
But since I have this base tag set, whenever my flex app adds the # to the URL, the page is now automatically redirected to the homepage.
So I really need to figure out a way to stop the TabNavigator from adding the # to the URL.
Any ideas?
Thanks!!
Turn off the history management in your Flex Builder project settings (in the Flex Compiler settings).
I was able to fix it by extending the TabNavigator and overriding these functions:
package
{
import mx.containers.TabNavigator;
public class MyTabNav extends TabNavigator
{
public function MyTabNav()
{
super();
}
override public function get historyManagementEnabled():Boolean
{
return false;
}
override public function set historyManagementEnabled(value:Boolean):void
{
return;
}
}
}
I am trying to add page with custom extension, say .asp2 with my set of html tags.
Now whenever i try to access the page on browser...it asks me "Save as". This happens because I am using an extn which the server is not able to recognise.
What should I do to so that my server, IIS 5.1 recognises this extension??
Please suggest
Also please suggest on how to associate custom events on such custom page?
In Internet Services Manager, right click on Default Web Site, select Properties, in Home Directory press the Configuration button. Click the Add button and fill the Executable field with the path to the aspnet_isapi.dll file and put asp2 in the Extension field.
Using a non-standard extension, you should also be sure to set the response's Content Type to text/html, so the browser knows how to interpret the document you're sending. Something like:
public class HttpHandler1 : IHttpHandler
{
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/html";
// Your code here.
}
}
In normal WebForms scenario, any root-relative URLs (e.g. ~/folder/file.txt) inside CSS files such as:
.form { background-image: url(~/Content/Images/form_bg.gif); }
will automatically get resolved during runtime if I specify
<head runat="server">
In the referencing page.
However, that is no longer happening on an ASP.NET MVC Beta1 website.
Is there a way I could enable this functionality without resorting to hacks or CSS-loader file? Like maybe HttpModules or something?
Or am I not desigining my website correctly? What is supposed to be a good design?
Since original ASP.NET WebForms already has this feature, I'd prefer to utilize any existing functionality if possible. But I don't have much clue.
This web application will be deployed in several environments where the ~ root folder might not be obvious.
EDIT: I mean the url in the file's CONTENT not the file's url itself.
I would not bother with the auto-root-finding ~ character. I understand that you want the same solution to work where the root directory differs between deployments, but within the CSS document you shouldn't have any problems using relative paths. The paths in the CSS document (to the image URL in your example) will always be relative to the location of the CSS file regardless of the path of any page that loads that CSS file. So if your images are in ~/Content/Images and your stylesheets are in ~/Content/Stylesheets, you'll always be able to use background-image: url(../Images/form_bg.gif); and it will work regardless of the location of the page that loads the stylesheet.
Is there a reason this wouldn't work?
One trick I have used in the past, was to actually make my CSS file have a .ASPX extension, and set the ContentType property in the page signature:
<%# Page Language="C#" ContentType="text/css" %>
body {
margin: 0;
padding: 0;
background: #C32605 url(<%= ResolveUrl("~/Content/themes/base/images/BodyBackground.png") %>) repeat-x;
font-family: Verdana, Arial, sans-serif;
font-size: small;
color: #d7f9ff;
}
This will ensure that the CSS file goes through the ASP.NET framework, and replaces the server side code with your relative path.
Here are some resources on implementing IHttpModule to intercept web requests to your app...
Write/adapt one to check for filetype (e.g. pseudocode: if (request ends with ".css") ...)
then use a regular expression to replace all instances of "~/" with System.Web.VirtualPathUtility.ToAbsolute("~/")
I don't know what this will do to performance, running every request through this kind of a filter, but you can probably fiddle with your web.config file and/or your MVC URL routes to funnel all .css requests through this kind of a filter while skipping past it for other files.
Come to think of it, you can probably achieve the same effect inside an ASP.NET MVC app by pointing all your CSS refrences at a special controller.action that performs this kind of preprocessing for you. i doubt that would be as performant as an IHttpModule though.
If you're trying to parse the ~/ out of any file, including text files, javascript, etc, you can write a handler that assigns a filter to it and you can use that to search for those paths... for example...
public class StringParsingFilter : MemoryStream {
public Stream OriginalStream {
get { return this.m_OriginalStream; }
set { this.m_OriginalStream = value; }
}
private System.IO.Stream m_OriginalStream;
public StringParsingFilter() : base() {
this.m_OriginalStream = null;
}
public override void Flush() {
this.m_OriginalStream.Flush();
}
public override void Write(byte[] buffer, int offset, int count) {
//otherwise, parse for the correct content
string value = System.Text.Encoding.Default.GetString(buffer);
string contentType = HttpContext.Current.Response.ContentType;
//Do any parsing here
...
//write the new bytes to the stream
byte[] bytes = System.Text.Encoding.Default.GetBytes(value);
this.m_OriginalStream.Write(bytes, offset, count + (bytes.Length - buffer.Length));
}
}
And you'll write a custom handler to know when to assign this filter... like the following...
public class FilterControlModule : IHttpModule {
public void Init(HttpApplication context) {
HttpApplication oAppContext = context;
oAppContext.BeginRequest += new EventHandler(_HandleSettingFilter);
}
private void _HandleSettingFilter(object sender, EventArgs e) {
//You might check the file at this part to make sure
//it is a file type you want to parse
//if (!CurrentFile.isStyleSheet()) { return; }
...
//assign the new filter
StringParsingFilter filter = new StringParsingFilter();
filter.OriginalStream = HttpContext.Current.Response.Filter;
HttpContext.Current.Response.Filter = (Stream)filter;
}
}
It may have actually been easier just to say "look up IHttpModules" but this is some code that I've used to parse files for paths other than ASP.net files.
You'll also have to change some things in your IIS settings to allow the files to be parsed by setting the ASP.net ISAPI to be a wildcard for all of the files that get handled. You can see more at this website, if you're using IIS6 that is...
You can also use this to modify any file types so you could assign some filters for images, some for javascript or stylesheets or ... really anything...
You could use an URL Rewriter to fix the URL as the request comes in, though I am not so sure it is so much elegant as a hack in this case.
I created a PathHelper util class that gives me all the paths I need.
For example
<link href="<%=PathHelper.CssUrl("FormulaIndex.css")%>" rel="Stylesheet" type="text/css"/>
Gives me the correct full url with the help of System.Web.VirtualPathUtility.ToAbsolute() and my own convention (content/css/yourFile.css).
I did the same for js, xml, t9n, pics...
Its central, reusable and now I only had to change one line to catch the move of the scripts folder from content/js to Scripts in all my websites and pages.
A moronic move if you ask me, but it's reality in the current beta :(