Home > OS >  How to replace identifiers with their associated values for off-site evaluation?
How to replace identifiers with their associated values for off-site evaluation?

Time:11-10

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>
  • Related