Don't miss out Virtual Happy Hour this Friday (April 26).

Try our conversational search powered by Generative AI!

Render EPiForms without using eval()

Vote:
 

Hi,

I've managed to deliver a EpiForm with with help of documentations (https://docs.developers.optimizely.com/content-cloud/v1.5.0-content-delivery-api/docs/content-delivery-api-and-optimizely-forms#formrenderingservicejs), Especially FormRendingService.js.

// This class use ES6 syntax. In case you want to use it in a browser that does not support ES6 syntax (i.e Internet Explorer 11 and below),
// you can copy/paste the render() function to your own script file and replace 'let' keyword with 'var'.
export default {
  render: (formModel, attachNode) => {
      // Initialize form js. Those scripts are used for all forms and only need to execute once, so we check here to make sure
      // when call this method second time, these scripts not execute again.
      if (window.epi == null || window.epi.EPiServer == null || window.epi.EPiServer.Forms == null) {
          // Those eval statements are safe because js strings come from the formModel
          // and formModel comes directly from serverside (not any script can intercept)
          window.eval(formModel.assets.originalJquery);
          window.eval(formModel.assets.jquery);            
      }

      // In case form has custom scripts for certain types of element.
      // ex: DateTimeElementBlock inherits from IElementRequireClientResources and so has its own resources
      // Those resources are different for each form so we have to execute the prerequisite script once for each form.
      window.eval(formModel.assets.prerequisite);        

      // Inject form's css
      let style = document.createElement('style');
      style.type = 'text/css';
      style.innerHTML = formModel.assets.css;
      document.getElementsByTagName('head')[0].appendChild(style);

      // Attach form html template to the attachNode
      let element = typeof attachNode === 'object' ? attachNode : document.getElementById(attachNode);

      // We use jQuery.html() here to allow to execute script embedded inside template of Forms' elements (.ascx files). 
      // The form HTML template also contains script of `formModel.assets.formInitScript` so we dont need to explicitly eval formInitScript
      window.jQuery(element).html(formModel.template);

      // Execute form viewmode script. We must set window.epi.EPiServer.Forms.__Initialized = false here otherwise
      // in case page has two or more forms, the second form's viewmode script will not be called.
      window.epi.EPiServer.Forms.__Initialized = undefined;
      eval(formModel.assets.viewModeJs);
  }

Actully the FomRenderingService.js using eval() function to inject JS files in to the window, now I'm getting security warnings from my greater team about this eval() function usage, because its leeds to security vialations it seems. 

Now I'm looking for an alternative way to inject javascript from Form Content Delivery API.

Anyone have suggestions to overcome this issue?

Thank you,

Hari

#299444
Edited, Apr 03, 2023 9:37
Vote:
 

I think this is safe enough already?

// Those eval statements are safe because js strings come from the formModel
// and formModel comes directly from serverside (not any script can intercept)

Additionally since the source is known to you then it is no problem in doing that. It is a plain string and eval just executes them as is. If you are unsure of source then you might need to store it differently - 

Function(formModel.jQuery)()

And keep in mind this post as well - 

https://stackoverflow.com/a/4599946/1982631

eval() evaluates a string as a JavaScript expression within the current execution scope and can access local variables.
new Function() parses the JavaScript code stored in a string into a function object, which can then be called. It cannot access local variables because the code runs in a separate scope.
#300689
Edited, Apr 25, 2023 11:00
Harinarayanan - Apr 26, 2023 13:13
Thanks, Manoj for highlighting. I had to change my implementation to regular page rendering since the requirement went huge.
However, I feel your points are valid, we are not receiving any JS from the user and rending just from the server.
This topic was created over six months ago and has been resolved. If you have a similar question, please create a new topic and refer to this one.
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.