Adding Protection to Your Code in Script Libraries

2 minute read time.

A partner recently asked me ""how can I discourage any fiddling with the code I have written for my customer"". The person who asked me this was anxious about two things. They wanted to make sure that their code didn't break, and they didn't want unauthorized people to 'borrow' their code for other purposes.

The actual code in question was included into the Opportunity Summary Screen of Sage CRM by adding an external script file reference into the custom content box of the OpportunityDetailBox screen.

e.g.

<script src=""..\\custompages/cs/csopportunityrules.js"">
</script>

The techniques that I will discuss equally apply for the way of referencing external file in Sage CRM. See the article: """">Script Libraries: Reusing Client Side Code Between Screens"".

The partner who had asked me the question had received support calls from their customer saying 'the code was broken' which they discovered was due to the customer's enthusiastic System Administrator attempting to make changes to the code without understanding the implications. It is reasonable to want to avoid errors creeping into the JavaScript code that has been written and is is also reasonable to want to discourage other people just taking and editing the code.

In this article I want to consider how we can start to add some level of protection to the code that has been written.

Good and Bad news

The bad news is that as far absolute code privacy is concerned this is pretty much impossible to secure for JavaScript. The JavaScript is delivered to the browser, and the techniques I'll discuss below will not deter the most determined 'hacker' from understanding your code. The good news is that we can go a long way to at least provide some 'security by obscurity' that should at least discourage the casual fiddlers who may want to edit and reuse your code.

Consider the code below from an external file I have used in the CompanyBoxLong screen. This contains reference to the Sage CRM Client Side API.

[code language=""javascript""]
///
//Create new CompanyRule object
var CompanyRules = CompanyRules || {};
//Add method to attached Google search to company name field
CompanyRules.addGoogleSearch = function () {
var fcomp_name = crm.fields(""comp_name"");
var strName = fcomp_name.text();
var strLink = ""<A HREF=http://www.google.com/search?q="";
if (fcomp_name.getMode() == ""view"") {
fcomp_name.text(strLink + escape(strName) + "" target=blank>"" + strName + ""</a>"")
};
}
//Highlight Closed Companies in Red
CompanyRules.addStatusWarning = function () {
if (crm(""comp_status"").value() == ""Closed"") {
crm(""comp_status"").highlight(""red"");
}
}
////
[/code]

We can ""minify"" or compress the code with a number of different online services e.g

But I use Google's Closure Compiler Service to generate either ""minified"" code or partially 'obfuscated' code.

This is really a tool for compressing JavaScript, stripping out the white-space and comments.

I have used the option for 'Simple' optimisation on the code I listed above.

If you look at the generated code below you will see that the tool has removed the white-space and comments and has also renamed the variables that I have used in my functions. This has two advantages, the first is that the code is slightly faster to load and secondly it makes the code much harder to read for the casual observer and therefore is more likely to discourage anyone from editing it.

[code language=""javascript""]
var CompanyRules=CompanyRules||{};CompanyRules.addGoogleSearch=function(){var a=crm.fields(""comp_name""),b=a.text();""view""==a.getMode()&&a.text(""<A HREF=http://www.google.com/search?q=""+escape(b)+"" target=blank>""+b+""</a>"")};CompanyRules.addStatusWarning=function(){""Closed""==crm(""comp_status"").value()&&crm(""comp_status"").highlight(""red"")};
[/code]

Why didn't I use the 'Advanced' optimization option?

The Advanced option will try to rename all of the variables including the objects like 'crm' which are external to the functions in the code used. This would have created errors in the code.