After reviewing dozens of Stack Overflow posts, I'm thoroughly confused. What I am trying to do is create a URL through an tag on one page that would open another webpage and run a function that requires two arguments. I thought this would be simple but I keep seeing references to "cross site scripting vulnerabilities" and I am not familiar with this potential security problem and feel like I am now playing with fire. I do not want to utilize something — even if the code works — if it opens up security risks. Could someone point me in the right direction with the correct (and most secure) way to do this? I can do my research (and learning) from there. Much appreciated.
For example you can append some parameter at the end of your URL
https://your-url/?parameter=hello
When this URL is opened on another webpage you can run JavaScript or a PHP function based on that URL query.
For JavaScript
getUrlParam(slug) {
let url = new URL(window.location);
let params = new URLSearchParams(url.search);
let param = params.get(slug);
if (param) {
return param;
} else {
return false;
}
}
console.log(getUrlParam('parameter'));
After that, you can run this function to check if any parameter is passed in that URL or not.
If this function returns that's given slug parameter you can run your custom code inside that if condition block
I am using the following Google Apps Script code to display content in a custom sidebar of my spreadsheet while the script runs:
function test() {
var sidebarContent = '1<br>';
updateSidebar(sidebarContent);
sidebarContent += '2<br>';
updateSidebar(sidebarContent);
sidebarContent += '3';
updateSidebar(sidebarContent);
}
function updateSidebar(content) {
var html = HtmlService.createHtmlOutput(content)
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setTitle('Sidebar')
.setWidth(250);
SpreadsheetApp.getUi().showSidebar(html);
}
It works, but each time the updateSidebar() function runs, the sidebar blinks when loading in the new content.
How can I program this to update the content of the sidebar more efficiently, thus removing the blink?
I'm assuming that SpreadsheetApp.getUi().showSidebar(html); should really only be run once, at the beginning, and the subsequent updates to the content should be handled by Javascript in a .js file.
But I don't know how to get the sidebarContent variable from Javascript code running client-side in the user's browser.
Also, I know this must be possible, because I just saw this post on the Google Apps Developer Blog today about an app that uses a custom sidebar, and the .gif towards the end of the article shows a nicely-animated sidebar that's being updated in real-time.
I believe the solution for this situation is to actually handle the flow of the server-side script from the client-side. That is the only way I can think of right now to pass data to the client side from the server without re-generating the HTML.
What I mean by this is that you would want to make the calls to the server-side functions from the client, and have them return a response as a success handler to the client. This means that each action that needs to be logged will need to be made into its own function.
Ill show you a quick example of what I mean.
Lets say your server-side GAS code looked like this:
function actionOne(){
...insert code here...
return true;
}
function actionTwo(){
...insert code here...
return true;
}
And so on for as many actions need to be executed.
Now, for your .html file, at the bottom you would have javascript looking something like this:
<script>
callActionOne();
function callActionOne(){
google.script.run.withSuccessHandler(callActionTwo).actionOne();
}
function callActionTwo(){
...update html as necessary to indicate that the first action has completed...
google.script.run.withSuccessHandler(actionsComplete).actionTwo();
}
function actionsComplete(){
..update html to indicate script is complete...
}
</script>
It is a bit more complex than is ideal, and you might need to use the CacheService to store some data in between actions, but it should help you with your problem.
Let me know if you have any questions or if this doesn't fit your needs.
Is there a way for a function (called by an IPython Notebook cell) to retrieve the content of a JavaScript variable (for example IPython.notebook.notebook_path which contains the path of the current notebook)?
The following works well when written directly within a cell (for example, based on this question and its comments):
from IPython.display import display,Javascript
Javascript('IPython.notebook.kernel.execute("mypath = " + "\'"+IPython.notebook.notebook_path+"\'");')
But that falls apart if I try to put it in a function:
# this doesn't work
from IPython.display import display,Javascript
def getname():
my_js = """
IPython.notebook.kernel.execute("mypath = " + "\'"+IPython.notebook.notebook_path+"\'");
"""
Javascript(my_js)
return mypath
(And yes, I've tried to make global the mypath variable, both from within the my_js script and from within the function. Also note: don't be fooled by possible leftover values in variables from previous commands; to make sure, use mypath = None; del mypath to reset the variable before calling the function, or restart the kernel.)
Another way to formulate the question is: "what's the scope (time and place) of a variable set by IPython.notebook.kernel.execute()"?
I think it isn't an innocuous question, and is probably related to the mechanism that IPython uses to control its kernels and their variables and that I don't know much about. The following experiment illustrate some aspect of that mechanism. The following works when done in two separate cells, but doesn't work if the two cells are merged:
Cell [1]:
my_out = None
del my_out
my_js = """
IPython.notebook.kernel.execute("my_out = 'hello world'");
"""
Javascript(my_js)
Cell [2]:
print(my_out)
This works and produces the expected hello world. But if you merge the two cells, it doesn't work (NameError: name 'my_out' is not defined).
I think the problem is related with Javascript being asynchronus while python is not. Normally you would think that the Javascript(""" python cmd """) command is executed, and then your print statment should work properly as expected. However, the Javascript command is fired but not executed. Most pobably it is executed after the cell 1 execution is fully completed.
I tried your example with sleep function. Did not help.
The asnyc problem can esaily be seen by adding an alert statement within my_js, but before kernel.execute line. The alert should be fired even before trying a python command execution.
But at the presence of print (my_out) statement within cell 1, you will again get the same error without any alerts. If you take the print line out, you will see the alert poping out within cell 1. But the varibale my_out is set afterwards.
my_out = None
del my_out
my_js = """
**alert ("about to execute python comand");**
IPython.notebook.kernel.execute("my_out = 'hello world'");
"""
Javascript(my_js)
There are other javascript utilities within notebook like IPython.display.display_xxx which varies from displaying video to text object, but even the text object option does not work.
Funny enough, I tested this with my webgl canvas application which displays objects on the HTML5 canvas; display.display_javascript(javascript object) works fine ( which is a looong html5 document) while the two pieces of words of output does not show up?! Maybe I should embed the output into canvas application somewhere, so it s displayed on the canvas :)
I wrote a related question (Cannot get Jupyter notebook to access javascript variables) and came up with a hack that does the job. It uses the fact that the input(prompt) command in Python does block the execution loop and waits for user input. So I looked how this is processed on the Javascript side and inserted interception code there.
The interception code is:
import json
from IPython.display import display, Javascript
display(Javascript("""
const CodeCell = window.IPython.CodeCell;
CodeCell.prototype.native_handle_input_request = CodeCell.prototype.native_handle_input_request || CodeCell.prototype._handle_input_request
CodeCell.prototype._handle_input_request = function(msg) {
try {
// only apply the hack if the command is valid JSON
console.log(msg.content.prompt)
const command = JSON.parse(msg.content.prompt);
const kernel = IPython.notebook.kernel;
// return some value in the Javascript domain, depending on the 'command'.
// for now: specify a 5 second delay and return 'RESPONSE'
kernel.send_input_reply(eval(command["eval"]))
} catch(err) {
console.log('Not a command',msg,err);
this.native_handle_input_request(msg);
}
}
"""))
The interception code looks whether the input prompt is valid JSON, and in that case it executes an action depending on the command argument. In this case, it runs the commend["eval"] javascript expression and returns the result.
After running this cell, you can use:
notebook_path = input(json.dumps({"eval":"IPython.notebook.notebook_path"}))
Quite a hack, I must admit.
Okay, I found a way around the problem: call a Python function from Javascript and have it do all of what I need, rather than returning the name to "above" and work with that name there.
For context: my colleagues and I have many experimental notebooks; we experiment for a while and try various things (in a machine learning context). At the end of each variation/run, I want to save the notebook, copy it under a name that reflects the time, upload it to S3, strip it from its output and push it to git, log the filename, comments, and result scores into a DB, etc. In short, I want to automatically keep track of all of our experiments.
This is what I have so far. At the bottom of my notebooks, I put:
In [127]: import mymodule.utils.lognote as lognote
lognote.snap()
In [128]: # not to be run in the same shot as above
lognote.last
Out[128]: {'file': '/data/notebook-snapshots/2015/06/18/20150618-004408-save-note-exp.ipynb',
'time': datetime.datetime(2015, 6, 18, 0, 44, 8, 419907)}
And in a separate file, e.g. mymodule/utils/lognote.py:
# (...)
from datetime import datetime
from subprocess import call
from os.path import basename, join
from IPython.display import display, Javascript
# TODO: find out where the topdir really is instead of hardcoding it
_notebook_dir = '/data/notebook'
_snapshot_dir = '/data/notebook-snapshots'
def jss():
return """
IPython.notebook.save_notebook();
IPython.notebook.kernel.execute("import mymodule.utils.lognote as lognote");
IPython.notebook.kernel.execute("lognote._snap('" + IPython.notebook.notebook_path + "')");
"""
def js():
return Javascript(jss())
def _snap(x):
global last
snaptime = datetime.now()
src = join(_notebook_dir, x)
dstdir = join(_snapshot_dir, '{}'.format(snaptime.strftime("%Y/%m/%d")))
dstfile = join(dstdir, '{}-{}'.format(snaptime.strftime("%Y%m%d-%H%M%S"), basename(x)))
call(["mkdir", "-p", dstdir])
call(["cp", src, dstfile])
last = {
'time': snaptime,
'file': dstfile
}
def snap():
display(js())
To add to the other great answers, there is a nuance of the browsers attempting to run the jupyter nb javascript magic on nb load.
To demonstrate: create and run the following cell:
%%javascript
IPython.notebook.kernel.execute('1')
Now save the notebook, close it and then re-open it. When you do that, under that cell suddenly you will see an error in red:
Javascript error adding output!
TypeError: Cannot read property 'execute' of null
See your browser Javascript console for more details.
That means the browser has parsed some js code and it tried to run it. This is the error in chrome, it will probably different in a different browser.
I have no idea why this jupyter javascript magic cell is being run on load and why jupyter notebook is not properly escaping things, but the browser sees some js code and so it runs it and it fails, because the notebook kernel doesn't yet exist!
So you must add a check that the object exists:
%%javascript
if (IPython.notebook.kernel) {
IPython.notebook.kernel.execute('1')
}
and now there is no problem on load.
In my case, I needed to save the notebook and run an external script on it, so I ended up using this code:
from IPython.display import display, Javascript
def nb_auto_export():
display(Javascript("if (IPython.notebook) { IPython.notebook.save_notebook() }; if (IPython.notebook.kernel) { IPython.notebook.kernel.execute('!./notebook2script.py ' + IPython.notebook.notebook_name )}"))
and in the last cell of the notebook:
nb_auto_export()
When a user clicks a button on my website I make an excel file on server-side and write it in the response.
HttpResponse httpResponse = Page.Response;
httpResponse.ClearHeaders();
httpResponse.ClearContent();
httpResponse.Clear();
httpResponse.Buffer = true;
httpResponse.AppendHeader("Content-Disposition",
"attachment; " +
"filename=\"" + fileName + "\";");
httpResponse.ContentType = "application/vnd.xlsx";
httpResponse.Charset = "";
using (MemoryStream memoryStream = new MemoryStream())
{
workbook.SaveAs(memoryStream);
memoryStream.WriteTo(httpResponse.OutputStream);
memoryStream.Close();
}
httpResponse.Flush();
httpResponse.End();
When I'm done writing this file, I would like a JavaScript script block to run, but I can't seem to make this work. I have heard that when I clear the response, I can't write a script block with the Page.ClientScript.RegisterStartupScript (deprecated?), since the user doesn't get the same page as the response, but I am hoping there's a workaround.
The button that makes the postback and fetches the file is not in an UpdatePanel, so I am unable to use the PageRequestManager.add_endRequest function that is implemented there. And I can't put the control into an UpdatePanel, since it won't allow me to write a file in an async postback.
Is there any other way to trigger a javascript function at the end of a postback? A JavaScript interval function that checks if a postback is in progress (or finished) is also an acceptable solution as well (but as far as I know, there is no way for JavaScript to "check" if a synchronous postback is in progress).
The Response.End() aborts the thread and sends the execution to Application_EndRequest.
Nothing can be done after that. You can either download the file or execute the javascript. But there is this solution using iframes.
I did try to find solution by myself and tried to fix it but without any good result. I assume it's probably something easy to fix but I got confused and decided it will be better to ask some more advanced people.
I am trying to do some small easy clicking game using javascript (+YUI library, JSON) and everything was fine the code was working, everything is ok as far as I was just using it as .html and simply opening the index.html by my browser (code in code.js and then index.html calling the script) but then I tried to upgrade it and make it to PHP and still everything looks alright till the momment when I launch my "website" by xampp and go to it by localhost, everything looks good and most of the code/website is working but by some reason one main function instead of working is giving me huge amount of text (It was not showing me everything, but this is what Firebug gave me):
<p id="add">function (a){this.push.apply(this,a);return this;}function (d){if(this.length<3){return null;}if(this.length==4&&this[3]==0&&!d){return"transparent"; }var b=[];for(var a=0;a<3;a++){var c=(this[a]-0).toString(16);b.push((c.length==1)?"0"+c:c);}return(d)?b:"#"+b.join("");}function (b){if(this.length!=3){return null; }var a=this.map(function(c){if(c.length==1){c+=c;}return c.toInt(16);});return(b)?a:"rgb("+a+")";}function (){for(var b=0,a=this.length;b</p>
The above code is not mine, it is the output of an "error" I have when I press the button to get credits, I do not have such lines nowhere in my source code and it is cut off at the end because it shows to me this way (firebug gave me whole part as stated above)
I don't have such lines in my code and this happens when for example I want to click on a button that will give me credit by clicking onto it (clicking game, You click on the button it will give You credit):
function credit() {
var a = game.credit+=100;
document.getElementById("add").innerHTML=Fix(a);
}
Do I have this problem because I need to use some other function/rewrite my code for PHP ? Or is it because I need to use some push function, or do I have something wrong with my apache? Or it's because of the document.getElementById and I should write it differently while using PHP?
Ps: game.credit because it's using different function too, and Fix(a) because it's using other function to beautify the result. Every other functions are working, only the ones that are responsible for adding the credit are showing me this text.
This is Fix function:
function Fix(what){
var str='';
what=Math.floor(what);
what=(what+'').split('').reverse();
for (var i in what) {
if (i%3==0 && i>0) str = ','+str;
str = what[i]+str;
}
return str;
}
#Edit
Ok I just did check it and it's this Fix function causing problem, everything works fine when I do not use it (for example I do: "document.getElementById("add").innerHTML=a;"). So what's wrong with this fix function, can someone help me make it work? This function is changing the numbers in example 1000 to 1,000 and not allowing it to be like 503.0203