Inline configuration
JSDefender supports partial protection. With inline configuration directives, you can set the protection options right in the source code. To define protection settings, you use JavaScript directives (similar to "use strict"
). In this section, you learn how to use the JSDefender inline configuration for partial protection.
- JavaScript Directives
- Using JSDefender Directives for Inline Configuration
- JSDefender inline configuration directives
- Program directives
- Function declaration directives
- Function expression directives
- Arrow function directives
- Class method directives
- Object method directives
- Inline protection directive formats
- Merging inline configuration settings
- Disabling the inline protection directives
- Global protection directives
JavaScript Directives
In JavaScript, directives are string literals placed at the beginning of the code or at the beginning of block statements. If you put any other statement into the code, subsequent string literals are not considered to be directives. This short code snippet demonstrates which literals are directives and which are not:
"directive #1";
"directive #2";
var counter = 0;
"this is not a directive";
"nor this";
function square(n) {
"directive #3";
var result = n * n;
"not a directive";
return result;
}
if (square(2) === 4) {
"directive #4";
console.log("test passes.");
"not a directive";
}
Using JSDefender Directives for Inline Configuration
Assume you want to apply Boolean literal replacement. With the CLI, you can issue this command:
jsdefender input.js protected.js -b
With inline configuration, you can add JSDefender directives to the source code:
"@jsdefender { booleanLiterals: true }";
var x = true;
var y = false;
function w() {
var x = false;
var y = true;
}
Now, you can omit the -b
switch from the command line to get the same result:
jsdefender input.js protected.js
The "@jsdefender { booleanLiterals: true }"
literal in the first line of the input is a valid JavaScript construct, called a directive. JavaScript uses it only in the "use strict"
mode.
JSDefender inline configuration directives
JSDefender directives start with the @jsdefender
prefix. Although JavaScript allows directives at the beginning of every block statement, JSDefender considers only these directives (and ignores the others):
- Program directives
- Directives that belong to functions (either declarations, standard function expressions, or arrow functions)
- Class method directives
- Object method directives
Let's see a few examples!
Program directives
"@jsdefender { booleanLiterals: true }";
const allow = true;
Function declaration directives
function myAcmeFunction(a, b) {
"@jsdefender { integerLiterals: true }";
return a + b;
}
Function expression directives
const myAcmeFunction = function (a, b) {
"@jsdefender { integerLiterals: true }";
return a + b;
};
Arrow function directives
const myAcmeFunction = (a, b) => {
"@jsdefender { integerLiterals: true }";
return a + b;
};
Class method directives
class myAcmeClass {
myAcmeMethod(a, b) {
"@jsdefender { integerLiterals: true }";
return a + b;
}
}
Object method directives
const myAcmeObj = {
myAcmeMethod(a, b) {
"@jsdefender { integerLiterals: true }";
return a + b;
},
};
Inline protection directive formats
The protection engine combines the directives with the jsdefender
prefix into a JSON string. For example, let's assume, you have these directives:
"@jsdefender {";
'@jsdefender "integerLiterals": {';
'@jsdefender "radix": "octal"';
"@jsedefender }";
"@jsdefender }";
JSDefender extracts the contents of these directives to this JSON:
{
"integerLiterals": {
"radix": "octal"
}
}
Of course, you can write this configuration with a single directive:
'@jsdefender { "integerLiterals": { "radix": "octal" } }';
For easier use, you can use the JavaScript object literal syntax, too (no need for single quotes or double quotes wrapping property names):
"@jsdefender {";
"@jsdefender integerLiterals: {";
'@jsdefender "radix": "octal"';
"@jsedefender }";
"@jsdefender }";
or
'@jsdefender { integerLiterals: { "radix": "octal" } }';
In the Named configuration sets section, you learned that you can use keys for a particular set of configuration options. You can use these keys within the inline configuration directives, like in this sample:
"@jsdefender medium";
medium
key.
You can also use the special named set keys, off
, disbale-inline
, and default
. For example, with this setting you can turn off the protection for the specialFunc
function:
function specialFunc() {
"@jsdefender off";
console.log("Entered into specialFunc");
// ...
}
Merging inline configuration settings
As you learned earlier in the Configuration merging section, the inline configuration settings are merged with the command line and configuration file settings. The inline configuration always overrides the others. When executing the protection process, JSDefender applies the closest inline configuration for each source code elements it transforms. This configuration mode allows setting up complex (but still easy-to-follow) protection scenarios.
For example, this input turns on Boolean literal replacement for the entire program:
"@jsdefender { booleanLiterals: true }";
var x = true;
var y = false;
function w() {
var x = false;
var y = true;
}
With this change, only the body of the w
function gets this protection:
var x = true;
var y = false;
function w() {
"@jsdefender { booleanLiterals: true }";
var x = false;
var y = true;
}
You can declare a scenario where everything, except the body of w
gets protected:
"@jsdefender { booleanLiterals: true }";
var x = true;
var y = false;
function w() {
"@jsdefender { booleanLiterals: false }";
var x = false;
var y = true;
}
This setup turns off only the Boolean literal transformation for the code within the w
function. Alternatively, you can turn off any protection:
"@jsdefender { booleanLiterals: true }";
var x = true;
var y = false;
function w() {
"@jsdefender off";
var x = false;
var y = true;
}
You can do more than just turn on or off a particular protection setting. You can adjust the options of a specific transform. For example, this code snippet turns on Boolean literal randomization within the body of w
:
"@jsdefender { booleanLiterals: true }";
var x = true;
var y = false;
function w() {
"@jsdefender { booleanLiterals: { randomize: true } }";
var x = false;
var y = true;
}
Keep in mind that setting a protection option to null
turns it off. So, here, the null
setting turns off Boolean literal replacement within the body of w
:
"@jsdefender { booleanLiterals: true }";
var x = true;
var y = false;
function w() {
"@jsdefender { booleanLiterals: null }";
var x = false;
var y = true;
}
Disabling the inline protection directives
There are scenarios when you want to disable the inline protection directives, for example, assessing performance changes, troubleshooting, or experimenting. There are several ways you can do that.
#1. The quickest way is to use the --disable-inline
command switch.
#2. Alternatively, you can add the "disableInline": true
property value to the configuration files.
#3. You can select individual files from the entire input to ignore the protection directives selectively. Let's assume this is the configuration of your input:
{
"inputs": ["file1.js", "file2.js"]
}
If you want to ignore the inline protection directives only for file2.js
, you can declare this intention:
{
"inputs": [
"file1.js",
{
"in": "file2.js",
"protection": "disable-inline"
}
]
}
#4: You can use inline directives for a part of a source code file:
"@jsdefender heavy";
init();
// ...
function init() {
"@jsdefender disableInline";
createObjects();
doAdditionalInit();
// ...
function createObjects() {
"@jsdefender { stringLiterals: true }";
// ...
}
function doAdditionalInit() {
"@jsdefender { localDeclarations: false }";
// ...
}
}
Even though you have directives within the createObjects
and doAdditionalInit
functions, those are ignored. The parent scope (init
) disables inline directives, so the protection ignores any other inline settings within init
.
Global protection directives
JSDefender applies a few inline protection directives only on the global (file) level:
- Date lock
- Domain lock
- DevTools blocking
- Console cloaking
- Global object hiding
If you use any of these options in an inline directive, JSDefender issues a warning message for each occurrence. Such directives do not stop the protection process; JSDefender ignores them.