I would like to have a tag:
<script src="https://mysource.com/script?foo=bar"></script>
https://mysource.com/script is a cloud function endpoint that returns a script that should run in the browser using bar
as a value for foo
. The script can't evaluate a function and simply send back the result because its expected behavior is to cause side effects like adding things to the window object.
I was able to do it by doing things like:
//prevents code injection like eval("evilcode")
function sanitize(){}
const foo = sanitize(req.query.foo);
const myFunc = ()=>{... <uses foo somewhere> ... <causes side effects> ...};
let strFunction = myFunc.toString();
strFunction = strFunction.replace("foo", foo);
const script = "(" strFunction ")();";
res.status(200).send(script);
But I can't help wonder if there is a better way to do it. Google does what I'm trying to do in their gtag scripts. If you go to https://www.googletagmanager.com/gtag/js?id=AW-950577603 and ctrl f AW-950577603 you'll see that the queried id (AW-950577603) appears inside the javascript code. But I have no idea if what they are doing is exactly what I'm doing or if they've done it in a better way. Suggestions?
CodePudding user response:
Your code:
const myFunc = ()=>{... <uses foo somewhere> ... <causes side effects> ...};
let strFunction = myFunc.toString();
strFunction = strFunction.replace("foo", foo);
const script = "(" strFunction ")();";
Instead of text-replacing foo
, you could make foo
a parameter:
const myFunc = (foo)=>{... <uses foo somewhere> ... <causes side effects> ...};
let strFunction = myFunc.toString();
const script = "(" strFunction ")(" foo ");";
CodePudding user response:
Your code:
//prevents code injection like eval("evilcode")
function sanitize(){}
const foo = sanitize(req.query.foo);
If you want req.query.foo
to appear as a JavaScript string literal, then JSON.stringify
often works:
const foo = JSON.stringify(req.query.foo);
CodePudding user response:
Normally, I'd store my client-side JavaScript code in a separate file. Separating client-side and server-side JavaScript helps me maintain my code. In your case, the file can expose a function called initializeMyApp
, and you can dynamically create a call to initializeMyApp
with the parameter-argument method explained in another answer. For example:
let strFunction = fs.readFileSync("initializeMyApp.js", "utf-8");
const script = "(" strFunction ")(" foo ");";
Even better: store your client-side JavaScript code in a separate file, and serve it as static content (possibly with a CDN). Then have the client code call initializeMyApp
in a separate <script>
:
<script src="https://mysource.com/script"></script>
<script>initializeMyApp("bar");</script>