how to get js context from htmlparser2 directly? - javascript

how to get js context from htmlparser2 directly?
var parser = new htmlparser.Parser({
onopentag: function(name, attribs){
if(name === "script" && attribs.type === "text/javascript"){
//console.log(text);
//console.log("JS! Hooray!");
}
},
ontext: function(text){
//fs.writeFileSync("../output/test.js",text.toString());
console.log(text);
},
onclosetag: function(tagname){
if(tagname === "script"){
//console.log("That's it?!");
}
}
}, {decodeEntities: true});
var input_src = fs.readFileSync('../input/test2.js', 'utf-8');
parser.write(input_src);
parser.end();
I try to get js from htmlparser2, but the content is not i am want.The content will include some other information expect the js. why the code do not work well?Could you give me some good ways to solve it?

You are not doing anything to limit the ontext function to only reading scripts. You need to set a flag whenever you encounter an opening script tag:
var inScriptElement = false;
var parser = new htmlparser.Parser({
onopentag: function(name, attribs){
if(name === "script" && attribs.type === "text/javascript"){
inScriptElement = true;
//console.log(text);
//console.log("JS! Hooray!");
}
},
ontext: function(text){
if (inScriptElement) {
//fs.writeFileSync("../output/test.js",text.toString());
console.log(text);
}
},
onclosetag: function(tagname){
if(tagname === "script"){
inScriptElement = false;
//console.log("That's it?!");
}
}
}, {decodeEntities: true});

Related

Google apps script function returns undefined in html

I am building an add-on for google docs (Just for practice) that will act like email. I already incorporated sending, receiving, deleting, and viewing messages. I added the code needed for a UI modal dialog, but one of the functions is only returning undfined. I tested this function in the code.gs file, and it worked perfectly. Here is a section of code.gs:
function onInstall() {
var html = HtmlService.createHtmlOutputFromFile('Startup').setWidth(350).setHeight(170);
DocumentApp.getUi().showModalDialog(html, 'New account:');
}
function testCheck() {
var ui = DocumentApp.getUi();
ui.alert(checkUsername(ui.prompt('').getResponseText(), ui.prompt('').getResponseText()));
}
function checkUsername(un, em) {
var i; var a; var is;
var props = PropertiesService.getScriptProperties();
if (props.getProperty(un) == null) {
is = true;
} else {
return 'This username is taken!';
}
if (em.length == 0) {
return true;
} else {
var len = (em.match(/#/g) || []).length;
if (len == 1) {
if (props.getProperty(em) != null) {
return 'Someone has already registered this email address as ' + props.getProperty(em);
} else {
return true;
}
} else {
if (em.indexOf(', ') != -1) {
em = em.split(', ');
} else if (em.indexOf('; ') != -1) {
em = em.split('; ');
} else if (em.indexOf(' + ') != -1) {
em = em.split(' + ');
} else if (em.indexOf(';') != -1) {
em = em.split(';');
} else if (em.indexOf(',') != -1) {
em = em.split(',');
} else if (em.indexOf('+') != -1) {
em = em.split('+');
} else if (em.indexOf(' ') != -1) {
em = em.split(' ');
} else {
return 'Please separate your email addresses with a comma, space, or semicolon.';
}
for (i = 0; i < em.length; i++) {
a = em[i];
if (props.getProperty(a) != null) {
return 'Someone has already registered ' + a + ' as ' + props.getProperty(a);
}
}
return true;
}
}
}
Here is the html file:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
</head>
<body>
Username:<br>
<input type='text' id='user' style='width:350px' maxlength='12'/><br>
Other email addresses:<br>
<textarea id='extras' style='width:350px' rows='2'></textarea><br>
<span class='error' id='err'></span><br>
<button class='action' onClick='check()'>Next</button>
<button onclick='group()'>Groups</button><br>
<script>
function check() {
var un = document.getElementById('user').value;
var em = document.getElementById('extras').value;
var fail = document.getElementById('err');
var is = google.script.run.checkUsername(un, em);
if (typeof is == 'string') {
fail.innerHTML = is;
} else {
google.script.host.close();
google.script.run.setAccount(un, em);
}
}
function group() {
var un = document.getElementById('user').value;
var em = document.getElementById('extras').value;
var is = google.script.run.checkUsername(un, em);
if (typeof is == 'boolean') {
setGroupAddress(un, em);
} else {
document.getElementById('err').innerHtml = is;
}
}
</script>
</body>
</html>
Update: I completely retyped the functions, but the program continues to return undefined. All inputs are the correct values, and the function returns information correctly in a ui.alert() box.
I figured it out after completely reading the Google Apps Script Documentation. The google.script.run.function() API does not return a value. In order to fetch data from a script, you must have the script generate raw HTML, and create a dialog with an HTML string.
Due to security considerations, scripts cannot directly return HTML to a browser. Instead, they must sanitize it so that it cannot perform malicious actions. You can return sanitized HTML using the createHtmlOutput API
function doGet() {
return HtmlService.createHtmlOutput('<b>Hello, world!</b>');
}
The code in the HtmlOutput can include embedded JavaScript and CSS. (This is standard client-side JavaScript that manipulates the DOM, not Apps Script). All of this content is sanitized using Google Caja, which applies some limitations to your client-side code. For more information, see the guide to restrictions in HTML service.
https://developers.google.com/apps-script/reference/html/html-output#

Specifying validation for specific form in some page

I have a javascript function that validate a popup form before submit it. Unfortunately it's created to handle one popup form per page only.
In my case, i have two different popup forms, so i want to specify what to do and also for which one.
$.fn.goValidate = function() {
var $form = this,
$inputs = $form.find('input:text');
var validators = {
email: {
regex: /^[\w\-\.\+]+\#[a-zA-Z0-9\.\-]+\.[a-zA-z0-9]{2,4}$/
}
};
var validate = function(klass, value) {
var isValid = true,
error = '';
if (!value && /required/.test(klass)) {
error = 'This field is required';
isValid = false;
} else {
klass = klass.split(/\s/);
$.each(klass, function(i, k){
if (validators[k]) {
if (value && !validators[k].regex.test(value)) {
isValid = false;
error = validators[k].error;
}
}
});
}
return {
isValid: isValid,
error: error
}
};
var showError = function($input) {
var klass = $input.attr('class'),
value = $input.val(),
test = validate(klass, value);
$input.removeClass('invalid');
$('#form-error').addClass('hide');
if (!test.isValid) {
$input.addClass('invalid');
if(typeof $input.data("shown") == "undefined" || $input.data("shown") == false){
$input.popover('show');
}
}
else {
$input.popover('hide');
}
};
$inputs.keyup(function() {
showError($(this));
});
$inputs.on('shown.bs.popover', function () {
$(this).data("shown",true);
});
$inputs.on('hidden.bs.popover', function () {
$(this).data("shown",false);
});
$form.submit(function(e) {
$inputs.each(function() {
if ($(this).is('.required') || $(this).hasClass('invalid')) {
showError($(this));
}
});
if ($form.find('input.invalid').length) {
e.preventDefault();
$('#form-error').toggleClass('hide');
}
});
return this;
};
$('form').goValidate();
I'm pretty sure that it's all about this line:
$('form').goValidate();
Let's say that the first form id is form_1 and the second form_2.
What should i put in this line?
Something like this i guess:
$('form['form_1]').goValidate();
Hope it was clear, thanks !
You can use form id to target your form.
ex. if your first form has id form1 then you can write.
$('#form1').goValidate();
and same as second one.

HTTP Parameter pollution attack

I developed a web application and deployed into the server and my security team come up with the below security remidiation issue.
Reflected HTML Parameter Pollution (HPP) is an injection weakness vulnerability that occurs when an attacker can inject a delimiter and change the parameters of a URL generated by an application. The consequences of the attack depend upon the functionality of the application, but may include accessing and potentially exploiting uncontrollable variables, conducting other attacks such as Cross-Site Request Forgery, or altering application behavior in an unintended manner. Recommendations include using strict validation inputs to ensure that the encoded parameter delimiter “%26” is handled properly by the server, and using URL encoding whenever user-supplied content is contained within links or other forms of output generated by the application.
Can any one have the idea about how to prevent HTML parameter pollution in asp.net
here is the script code in the webpage
<script type="text/javascript" language="javascript">
document.onclick = doNavigationCheck ;
var srNumberFinal="";
function OpenDetailsWindow(srNumber)
{
window.open("xxx.aspx?SRNumber="+srNumber+ "","","minimize=no,maximize=no,scrollbars=yes,status=no,toolbar=no,menubar=no,location=no,width=800,directories=no,resizable=yes,titlebar=no");
}
function OpenPrintWindow()
{
var querystrActivityId = "<%=Request.QueryString["activityId"]%>";
if(querystrActivityId != "")
{
var url = "abc.aspx?id=" + "<%=Request.QueryString["id"]%>" + "&activityId=" + querystrActivityId + "";
}
else
{
var hdrActivityId = document.getElementById('<%=uxHdnHdrActivityId.ClientID%>').value;
var url = "PrintServiceRequestDetail.aspx?id=" + "<%=Request.QueryString["id"]%>" + "&activityId=" + hdrActivityId + "";
}
childWinReference=window.open(url, "ChildWin","minimize=yes,maximize=yes,scrollbars=yes,status=yes,toolbar=no,menubar=yes,location=no,directories=no,resizable=yes,copyhistory=no");
childWinReference.focus();
}
function NavigateSRCopy(srNumber)
{
srNumberFinal = srNumber;
if (srNumber != "undefined" && srNumber != null && srNumber != "")
{
new Ajax.Request('<%= (Request.ApplicationPath != "/") ? Request.ApplicationPath : string.Empty %>/xxx/AutoCompleteService.asmx/CheckFormID'
, { method: 'post', postBody: 'srNumber=' + srNumber, onComplete: SearchResponse });
}
}
function SearchResponse(xmlResponse)
{
var xmlDoc;
try //Internet Explorer
{
xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async="false";
xmlDoc.loadXML(xmlResponse.responseText);
}
catch(e)
{
try // Firefox, Mozilla, Opera, etc.
{
parser=new DOMParser();
xmlDoc=parser.parseFromString(xmlResponse.responseText,"text/xml");
}
catch(e)
{
alert(e.message);
return;
}
}
if(xmlDoc.getElementsByTagName("string")[0].childNodes[0] != null)
{
formID = xmlDoc.getElementsByTagName("string")[0].childNodes[0].nodeValue;
}
else
{
formID = null;
}
if(formID != null && formID != "")
{
window.location.href = '/CustomerSupportRequest/CreateServiceRequest.aspx?id=' + formID + '&TemplateSR=' + srNumberFinal + '&Frompage=CopySR';
return true;
}
else
{
alert("This Service Request cannot be copied because it meets at least one of these conditions: \t\t\n\n * It was created prior to 10/15/2008 \n * It was auto generated as part of the Report Requeue Process \n * It was auto generated as part of the ERA Requeue Process \n * It was not created online");
}
}
function UpdateChildCases()
{
var modalPopup = $find('modalParentChildComments');
modalPopup.show();
}
function HideParentChildPopup()
{
var modalPopup = $find('modalParentChildComments');
modalPopup.hide();
return false;
}
function HideErrorSRNumsPopup()
{
var modalPopup = $find('modalParentErrorSRNumDisplay');
modalPopup.hide();
return false;
}
function HideRetrySRNumsPopup()
{
var modalPopup = $find('modalRetrySRNumDisplay');
modalPopup.hide();
return false;
}
function RemoveParent_ChildFlag(type)
{
var childCases = document.getElementById("<%=uxHdnChildCases.ClientID %>");
var msg = "";
var btn;
if(type == "Child")
{
if(childCases.value.indexOf(',') != -1)
msg = "Are you sure you want to remove the Child flag from this Service Request?";
else
msg = "This is the only child associated to the parent case. Removing the child flag will also remove the parent flag from the associated case. Choose OK to remove the flags, or Cancel to close this dialog";
btn = document.getElementById('<%=uxRemoveChildFlag.ClientID%>');
}
else
{
msg = "Removing the parent flag from this case will also remove the child flag from all associated cases. Are you sure you want to remove the Parent flag from this Service Request?";
btn = document.getElementById('<%=uxRemoveParentFlag.ClientID%>');
}
if(btn)
{
if(!confirm(msg))
{
return false;
}
else
{
btn.click();
}
}
}
function limitTextForParentChildComments()
{
var objLblCharCount = document.getElementById('uxLblPCCharCount');
var objTxtComments = document.getElementById('<%=txtParentComment.ClientID%>');
if (objTxtComments.value.length > 1500)
{
objTxtComments.value = objTxtComments.value.substring(0, 1500);
}
else
{
objLblCharCount.innerHTML = 1500 - objTxtComments.value.length + " ";
}
setTimeout("limitTextForParentChildComments()",50);
}
function ValidateInputs()
{
var lblErrorMessage = document.getElementById('<%=lblCommentErrorTxt.ClientID%>');
var objTxtComments = document.getElementById('<%=txtParentComment.ClientID%>');
if(objTxtComments.value.trim() == "")
{
lblErrorMessage.style.display = "block";
return false;
}
}
</script>
As per OWASP Testing for HTTP Parameter pollution, ASP.NET is not vulnerable to HPP because ASP.NET will return all occurrences of a query string value concatenated with a comma (e.g. color=red&color=blue gives color=red,blue).
See here for an example explanation.
That said, your code appears to be vulnerable to XSS instead:
var querystrActivityId = "<%=Request.QueryString["activityId"]%>";
If the query string parameter activityId="; alert('xss');" (URL encoded of course), then an alert box will trigger on your application because this code will be generated in your script tag.
var querystrActivityId = ""; alert('xss');"";

javascript if() dont work

I have PHP and JS script for uploading image. PHP file returns a var err:type and I'm checking in JS if return == err:type, but it doesn't work.
$(document).ready
(
function()
{
$('#avatar_image_upload_form').submit
(
function()
{
$('div#avatar_ajax_upload_demo img').attr('src','../../Files/Border/loading.gif');
}
);
$('iframe[name=avatar_upload_to]').load(
function()
{
var result = $(this).contents().text();
if(result !='')
{
$('div#avatar_ajax_upload_demo img').attr('src',result);
if(result == 'err:size')
{
$('div#avatar_ajax_upload_demo img').attr('src','../../Files/Border/avatar_big.jpg');
}
if (result == 'err:type')
{
$('div#avatar_ajax_upload_demo img').attr('src','../../Files/Border/avatar_invalid.jpg');
}
}
}
);
}
);
if(result == 'err:type') doesn't work, but result = "err:type"
According to this image:
There are a lot of white lines at the beginning of the string. You need to trim the result string to remove them:
var result = $(this).contents().text().trim();
You should best fix your PHP code in order not to send those blank lines.
[WRONG]
Maybe your error is here : (if avatar_upload_to isn't a variable)
$('iframe[name=avatar_upload_to]').load(
Should be
$('iframe[name="avatar_upload_to"]').load(
=====
[TEST]
What appends if you make this :
$('iframe[name=avatar_upload_to]').load(
function()
{
var result = $(this).contents().text();
console.log(result);
//or
alert(':'+result+':');
if(result !='')
{
$('div#avatar_ajax_upload_demo img').attr('src',result);
if(result == 'err:size')
{
$('div#avatar_ajax_upload_demo img').attr('src','../../Files/Border/avatar_big.jpg');
}
if (result == 'err:type')
{
$('div#avatar_ajax_upload_demo img').attr('src','../../Files/Border/avatar_invalid.jpg');
}
}
}
);

Running script tags fetched with jsonp

Edit: Resolved, see answer below.
The problem I'm trying to solve is an ad loading script, that loads the ad code with jsonp and inserts it into the dom.
Now sometimes the ad code will include javascript tags, and from some posts here on stackoverflow i got the idea that moving them to head of the document to make them run, which after some experimentation prompted me to ask this question:
Appending scripts to head using javascript - weird behavior
My question there was solved but the problem remains, the scripts i insert into my test div does not run, nor do they run when moved to the head.
I have a code example here:
http://m.iijax.com/p1.html
And a simple jsonp example here:
http://m.iijax.com/p2.php
The code in p2 will try to log a message to the console, alert a message, and set a variable which i then try to print out, and all of these things fails.
Is the only way to run code like this using the eval function or am I doing some basic mistake?
Here is the code for the first part:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
if (typeof JSONP === 'undefined') {
/*Lightweight JSONP fetcher - www.nonobtrusive.com*/
var JSONP = (function(){
var counter = 0, head, query, key, window = this;
function load(url) {
var script = document.createElement('script'),
done = false;
script.src = url;
script.async = true;
script.onload = script.onreadystatechange = function() {
if ( !done && (!this.readyState || this.readyState === "loaded" || this.readyState === "complete") ) {
done = true;
script.onload = script.onreadystatechange = null;
if ( script && script.parentNode ) {
script.parentNode.removeChild( script );
}
}
};
if ( !head ) {
head = document.getElementsByTagName('head')[0];
}
head.appendChild( script );
}
function jsonp(url, params, callback) {
query = "?";
params = params || {};
for ( key in params ) {
if ( params.hasOwnProperty(key) ) {
query += encodeURIComponent(key) + "=" + encodeURIComponent(params[key]) + "&";
}
}
var jsonp = "json" + (++counter);
window[ jsonp ] = function(data){
callback(data);
window[ jsonp ] = null;
try {
delete window[ jsonp ];
} catch (e) {}
};
load(url + query + "callback=" + jsonp);
return jsonp;
}
return {
get:jsonp
};
}());
}
JSONP.get( 'http://m.iijax.com/p2.php', { requestType:'demoRequest'}, function(data){
var adC = document.getElementById("testId");
adC.innerHTML = data.code;
// Move script tags to head
var scripts = adC.getElementsByTagName("script");
for(i=scripts.length - 1;i>-1;i--) {
document.head.appendChild(scripts[i]);
}
// Now check value of var letsSeeIfThisIsDefined, set in the fetched code
console.log(letsSeeIfThisIsDefined);
});
</script>
</head>
<body>
<div id="testId"></div>
</body>
</html>
The answer seems a little bloated. Here's my version:
function execJSONP(url, cb) {
var script = document.createElement('script');
script.async = true;
var callb = 'exec'+Math.floor((Math.random()*65535)+1);
window[callb] = function(data) {
var scr = document.getElementById(callb);
scr.parentNode.removeChild(scr);
cb(data);
window[callb] = null;
delete window[callb];
}
var sepchar = (url.indexOf('?') > -1)?'&':'?';
script.src = url+sepchar+'callback='+callb;
script.id = callb;
document.getElementsByTagName('head')[0].appendChild(script);
}
Thanks to this post:
Executing <script> elements inserted with .innerHTML
I was able to modify my code a little, I now pick out the data from the script tags fetched with jsonp, put it into newly created script tags and append them to the head and it works. :)
Here is the revised code, including the new function parseScripts():
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
function parseScripts(elementId) {
// Get the div where code has been inserted by innerHTML
var td = document.getElementById(elementId);
// Find any script tags in that code
var scripts = td.getElementsByTagName("script");
for(i=scripts.length - 1;i>-1;i--) {
// For each script found pick out the data
var elem = scripts[i];
var data = (elem.text || elem.textContent || elem.innerHTML || "" );
// Create a new script element and add the data
var script = document.createElement("script");
script.type = "text/javascript";
try {
// doesn't work on ie...
script.appendChild(document.createTextNode(data));
} catch(e) {
// IE has funky script nodes
script.text = data;
}
// Append new script tag to head of document
document.head.appendChild(script);
}
}
if (typeof JSONP === 'undefined') {
/*Lightweight JSONP fetcher - www.nonobtrusive.com*/
var JSONP = (function(){
var counter = 0, head, query, key, window = this;
function load(url) {
var script = document.createElement('script'),
done = false;
script.src = url;
script.async = true;
script.onload = script.onreadystatechange = function() {
if ( !done && (!this.readyState || this.readyState === "loaded" || this.readyState === "complete") ) {
done = true;
script.onload = script.onreadystatechange = null;
if ( script && script.parentNode ) {
script.parentNode.removeChild( script );
}
}
};
if ( !head ) {
head = document.getElementsByTagName('head')[0];
}
head.appendChild( script );
}
function jsonp(url, params, callback) {
query = "?";
params = params || {};
for ( key in params ) {
if ( params.hasOwnProperty(key) ) {
query += encodeURIComponent(key) + "=" + encodeURIComponent(params[key]) + "&";
}
}
var jsonp = "json" + (++counter);
window[ jsonp ] = function(data){
callback(data);
window[ jsonp ] = null;
try {
delete window[ jsonp ];
} catch (e) {}
};
load(url + query + "callback=" + jsonp);
return jsonp;
}
return {
get:jsonp
};
}());
}
JSONP.get( 'http://m.iijax.com/p2.php', { requestType:'demoRequest'}, function(data){
var adC = document.getElementById("testId");
adC.innerHTML = data.code;
// Try and run the scripts
parseScripts("testId");
});
</script>
</head>
<body>
<div id="testId"></div>
<div style="height: 0px; width: 0px; border: 10px solid transparent; border-left-color: #505050;"></div>
</body>
</html>

Categories

Resources