Wagtail insert code into body (streamfield) - wagtail

Is it possible to insert html in any other way than RawHTML? RawHTML is a threat and was wondering if I could do it another way.
Thanks in advance!

As #gasman says in his comment on the question, inserting HTML carries the same risks no matter what form field you give your editors to do it.
However, you can implement a .clean() method on your block type which sanitises the HTML using Bleach.
e.g. to allow only <p> tags:
>>> raw_html = """<p id='foo' class='dangerous'>
<script>console.log('bar');</script>
<b>Hello</b>
</p>"""
>>> html = bleach.clean(raw_html,
tags=['p'],
attributes={'p': ['id']},
strip=True)
>>> print(html)
<p id='foo'>Hello</p>

Related

How can my template include an element whose type is determined by an expression in angularjs?

It's 2022 and sadly I'm learning AngularJS (already past end of life!)
I need need to use what might be called a dynamic element/component. Pseudocode example:
In controller:
this.theElementName = 'b';
In the template:
<{{$ctrl.theElementName}}>this is some text</{{$ctrl.theElementName}}>
I would want this to create <b>this is some text</b>.
The reason is that I want to generate an array of different directives to render, and I don't want code like:
<b ng-if="$ctrl.theElementName === 'b'">this is some text</b>
<div ng-if="$ctrl.theElementName === 'div'">this is some text</div>
<directive-abc ng-if="$ctrl.theElementName === 'directive-abc'">this is some text</directive-abc>
...
In Svelte, it's
<svelte:element this={theElementName} />
In Vue it's
<div :is="theElementName" />
EDIT: in response to the reluctant 'that person', clarifying the use-case
Consider a user-configurable UI. The result of the configuration might be an array list of components desired. I would then need to loop and output those different components in my template. Of course the components would need a standard interface for properties passesd in, events emitted etc. but that can all be designed for.
My code could do a big switch statement, but that requires prior knowledge of every possible component that might be used now or in the future. By doing it the way I intend to, however, a future person could add a component without needing to touch this code.
You can write directive my-directive to use:
<div my-directive="$ctrl.theElementName">...
to generate:
<div><component-a>...
<div><component-b>...
<div><component-c>...
All directive should do is to generate html string and compile it:
element.append($compile('<' + scope.myDirective + '>...')(scope))
(also remember to update content in onChanges if you want to support it)
Directive may also copy certain/all attributes from original element etc.
P.S. you should be cautious e.g. if component name comes from database that may allow injections.
Not a brilliant solution, but documenting what is more of a workaround.
ng-include can be used to source another template file. That file can contain the component you need to include.
<ng-include src="'/path/to/' + theElementName + '.html'"></ng-include>

Getting wordpress posts with react shows special chars instead of apostrophe

I am getting what I am assuming is json data from a wordpress blog endpoint like so:
https://example.com/wp-json/wp/v2/posts
I am looping through and showing the tiles for now:
<div>{posts && posts.map((post) => <h1>{post.title.rendered}</h1>)}</div>
But the post titles are not displaying properly. For example the word Don't shows Don’t
I have discovered that I can use dangerouslySetInnerHTML to fix this issue but is it safe? The fact that it has the word 'dangerously' in it is worrying.
I believe dangerouslySetInnerHTML is the way to go about this - but I will go into more detail as to why "dangerously" is in "dangerouslySetInnerHTML" and hopefully that will help you make an informed decision for your situation.
What dangerouslySetInnerHTML does is render any HTML string given to it within the DOM element.
For example:
<h1 dangerouslySetInnerHTML={{__html: post.title.rendered}} />
(as an aside, note the __html key has two underscores)
Will properly render the string Don’t to Don't.
This is all pretty harmless, however, if, for example, the value of post.title.rendered could be set by an untrusted party (such as an arbitrary user), and if this arbitrary user wanted to do some damage, they could enter a string such as:
<script type="text/javascript>
// Do evil stuff
console.log('I did some evil stuff');
</script>
This code would then be executed by the browser when the page loads - because React would have generated the following DOM:
<h1>
<script type="text/javascript>
// Do evil stuff
console.log('I did some evil stuff');
</script>
</h1>
So with all that in mind, if you are sure that the value of this field is within your control (and not anyone else's) and you also know that there will not be any arbitrary code in these strings, then go ahead and use dangerouslySetInnerHTML.
However, if there is the possibility that someone besides yourself could manipulate this field, I would instead look to something like decode-html-entities - this way you can have the presentation you want, without compromising your app/users.

How to get the text associated with a checkbox in Java

I have below html, how can i get the chechbox names?
<html>
<body>
<form>
<input type="checkbox" name="Countries" value="US">Unites States</input>
<input type="checkbox" name="Countries" value="UK">United Kingdom</input>
</form>
</body>
</html>
I tried below, but none helps:
List<WebElement> eles=driver.findElements(By.name("Countries"));
Integer ddSize=eles.size();
for(Integer i=0;i<ddSize;i++)
System.out.println(eles.get(i).getText());
or
for(WebElement ele:eles)
System.out.println(ele.getText());
also tried ele.getAttribute("text") etc...
You can write a code something like below:
List<WebElement> checkboxes=driver.findElements(By.xpath("//input[#type='checkbox']"));
for (WebElement checkbox: checkboxes) {
System.out.println(checkbox.getText());
Hope it helps!
There was an issue raised long time back -
https://code.google.com/p/selenium/issues/detail?id=2922
Quoting from that issue -
Closing as fixed, it is decided long ago that getText returns empty
string for input elements, a user should use getAttribute("value").
Your html code already has a "value" inside your input tag making things a bit hard though.
According to w3schools regarding usage of "value" attribute -
For "checkbox", "radio", "image" - it defines the value associated
with the input (this is also the value that is sent on submit)
So, I believe there won't be a need to include an extra text (like the United States and United Kingdom in your code) for an "input" element with "checkbox" as this is in standard practice taken care of, by using the "value" attribute for the checkbox.
Please use the below code to get the value of Checkboxes.
List<WebElement> eles=driver.findElements(By.name("Countries"));
Integer ddSize=eles.size();
for(Integer i=0;i<ddSize;i++)
System.out.println(eles.get(i).getAttribute("value"));
I've modified your code instead of getting the text value you need to use getAttribute("value") method with attribute as value.
Your output would be something like:
US
UK
If you just want to print the values you can also do that by using below line of command.
System.out.println(driver.findElement(By.xpath("html/body/form")).getText());
This will give output as mentioned below, b'coz your text is tagged with form tag not with input tag:
Unites States United Kingdom
hope it helps! :)
Selenium Webdriver treats innerHTML as an attribute, so you could use
String text = ele.getAttribute("innerHTML");
moreover, the getText() will not work well with the input element
This post will explain you about RC too here
Edit: as per OP comments
innerHTML will work well with most of the browsers. Or you can use javascript executor to do it.
String text = (String)(JavascriptExecutor (driver)).executeScript("return arguments[0].innerHTML;", ele);
You can look at this post for more insights

angularjs + cross-site scripting preventing

Is Angularjs takes care of XSS attack. I have read that ng-bind takes care. But When i try to do a sample to test that, it allows me to insert html tags in input type with ng-model...it didn't escape the Html tags.
I have lot of input element in our page, which binds with ng-model, what should I do to make sure if I input a html tags ,angular ignores the html/scrip tags.
ex.
<input id="name" ng-model="name"></input>
if I input as
'Hello, <b>World</b>!'
$scope.name contains the same what I entered ,didn't exclude the tags. i.e
var val = $scope.name;
console.log(val);
prints as same
'Hello, <b>World</b>!'
Please let me know how to solve this in angularjs.
thank
Look at here : http://docs.angularjs.org/api/ngSanitize/service/$sanitize
If you want escape use ng-bind, it ll render the tag without interpretation like that :
Hello <b>World</b> not like Hello World !
Do you understand ? so ng-bind is safe because it doesn't care about HTML tags.
If you want that your HTML tags be interpreted but safely just use ng-bind-html !
For example if you want to display this string :
'Hello <b>World</b><input type="text" />'
The result will be : Hello World but without the input because AngularJS compiler uses $sanitize service and check a whitelist of HTML elements and an iput is not authorized.
Maybe ng-bind-html is what you're looking for.
If you just want be sure that the user can't put html tags in your input just use the directive ng-pattern on your inputs !
http://docs.angularjs.org/api/ng/directive/input
It takes a regex for allowed characters in your input !
Hope it helps !
I don't believe that AngularJS has default whitelist input validation, which is what your test exercises. So a user can pretty much input anything they like. This is not surprising - whitelists are very domain specific, and Angular is a framework designed for a wide range of domains.
The main defense against XSS is to properly encode all untrusted data (see https://www.owasp.org/index.php/Top_10_2013-A3-Cross-Site_Scripting_(XSS)). This, Angular does by default.
Bottom line is that AngularJS is intended to be secure from XSS by default, no special action required. You can verify some basic scenarios by trying to output what you input into a view using the normal {{scopevariable}} notation.
I did find a detailed analysis of AngularJS XSS vulnerability: https://code.google.com/p/mustache-security/wiki/AngularJS. At the end of the comments, there is a link to a google doc with further discussion and response from the angular team.

AngularJS insert invalid HTML

I have an app that requires HTML to be pieced together from different APIs. Rather than getting into specifics there, let me just say that we have tried getting away from that many times but in the end the best answer always end up being what we currently have. Hopefully that changes someday but for now it's working great.
Currently, the HTML is parsed together as a string server-side using NodeJS and sent across the wire as complete HTML to be rendered. I'm in the process of adopting AngularJS, and while I'm loving it I am stuck on this issue-- how can I use Angular templating to insert invalid HTML at times?
The server will return three JSON fields: leadingHTML, trailingHTML, and copy. The copy field is always valid HTML, but leadingHTML and trailingHTML can sometimes return invalid HTML. When all three are added together, valid HTML results.
Let me illustrate:
leadingHTML='<figure>';
copy = '<img src="img1.jpg"/><img src="im2.jpg"/><figcaption>I love AngularJS</figcaption>';
trailingHTML='</figure>';
As you can see, if you add those together you will get the valid HTML that is required to be displayed. It's pretty easy to make the fields trustworthy HTML in Angular:
for (i in data.results){
data.results[i].copy=$sce.trustAsHtml(data.results[i].copy);
data.results[i].leadingHTML =$sce.trustAsHtml(data.results[i].leadingHTML );
data.results[i].trailingHTML =$sce.trustAsHtml(data.results[i].trailingHTML );
}
And then render the copy in my view:
<div ng-repeat='i in data.result'>
<p ng-bind-html='i.copy'></p>
</div>
But I need a way that does what this looks like it would do, but the leadingHTML and trailingHTML scope variables get render as strings:
<div ng-repeat='i in data.result'>
{{ i.leadingHTML }}
<p ng-bind-html='i.copy'></p>
{{ i.trailingHTML }}
</div>
Is the best answer here to build the template via javascript? Would that even work?
Are you able to pre-process your data so that you do have valid HTML?
var item;
for (i in data.results){
item = data.results[i];
item.content = $sce.trustAsHtml(item.leadingHTML + item.copy + item.trailingHTML);
}
Then you can just bind to the combined content in the view:
<div ng-repeat='i in data.results'>
<div ng-bind-html='i.content'></div>
</div>
Edit:
Yes, this will allow you to embed expressions in your HTML content.
In fact, you will need to be careful that you aren't opening yourself up to security exploits in the trusted HTML content (see the example at the bottom of the page for the $sce service).
Using $sce.trustAsHtml in this way is roughly equivalent to loading a directive's templateUrl from your site, so the security considerations around that are probably the same. See the "How does it work?" and
"Impact on loading templates".

Resources