Obfuscation is the process of making your code unclear and unreadable to humans. This adds a level of security to source code specially in web world were source code is readily available. Minification is the process of removing unnecessary data present in code resulting in smaller file sizes and faster loading. In this tutorial we will focus on making a simple build system which detects every javascript file in our source code to obfuscate and minify.
Prerequisites
To follow this tutorial you need basic knowledge of Javascript and Nodejs. We will use javascript-obfuscator to obfuscate and minify code.
Let's go...
Installation
We will only use one external library javascript-obfuscator which can be installed as a dev dependency.
npm install --save-dev javascript-obfuscator
Imports & Folders
In total we need three libraries - fs, path and javascript-obfuscator.
const Fs = require('fs');
const Path = require('path');
const JavaScriptObfuscator = require('javascript-obfuscator');
The source code will be kept in src folder and final build files will be generated in build folder.
const src = Path.join(__dirname, '/src/');
const build = Path.join(__dirname, '/build/');
Read directories
All the directories will be read recursively and find javascript files which will be than obfuscated and minified. To read files we will use fs module.
function readDirectory(dirPath)
{
Fs.readdir(dirPath, (err, files) =>
{
if(err)
{
console.error("Could not list directory.", err);
process.exit(1);
}
files.forEach((file, index) => // loop through every file
{
let path = Path.join(dirPath, file);
console.log(path);
});
});
}
This will give us path of every file and folder in the provided directory. But we need to read differentiate between files and directories and further read the directories found. This can be done through stat
function provided by fs.
Fs.stat(path, (err, stat) =>
{
if(err)
{
console.log("error in stating file.", err);
return;
}
if(stat.isFile())
{
console.log(`${path} is a file`);
}
else if(stat.isDirectory())
{
console.log(`${path} is a folder`);
readDirectory(path); // Further read the folder.
}
});
Copy files and directories from src to build directory
Now this is perfect time that we start copying all the files found in src to build directory. While copying we will simultaneously also create absent directories present in src.
if(stat.isFile())
{
const newPath = path.replace(src, build); // Replace src path with build path.
Fs.copyFileSync(path, newPath); // Copy file from old path in src to new path in build.
if(newPath.endsWith(".js")) // Check if it is javascript file.
{
obfuscate(newPath); // Obfuscate copied file in build folder.
}
}
else if(stat.isDirectory())
{
var newDir = path.replace(src, build); // Replace src path with build path.
if (!Fs.existsSync(newDir)) // Check if directory exists or not.
{
Fs.mkdirSync(newDir); // Create new directory.
}
readDirectory(path); // Further read the folder.
}
Obfuscation and Minification
Finally, javascript file found will be obfuscated and minified. To do so, we will use JavaScriptObfuscator.obfuscate
function which takes code as first argument and a config object as second.
function obfuscate(filePath)
{
const content = Fs.readFileSync(filePath).toString(); // Read the files content.
var result = JavaScriptObfuscator.obfuscate(content,
{ // Config for obfuscation
compact: true, // Set true to enable minification
controlFlowFlattening: true,
target: 'browser'
}
); // Generated minified and obfuscated code
Fs.writeFileSync(filePath, result.getObfuscatedCode()); // Write obfuscted and minified code generated back to file.
}
You can read more about the config options here.
Finally...
Here is the full code
const Fs = require('fs');
const Path = require('path');
const JavaScriptObfuscator = require('javascript-obfuscator');
const src = Path.join(__dirname, '/src/');
const build = Path.join(__dirname, '/build/');
readDirectory(src); // Start reading with src directory.
function readDirectory(dirPath)
{
Fs.readdir(dirPath, (err, files) =>
{
if(err)
{
console.error("Could not list directory.", err);
process.exit(1);
}
files.forEach((file, index) => // loop through every file
{
let path = Path.join(dirPath, file);
Fs.stat(path, (err, stat) =>
{
if(err)
{
console.log("error in stating file.", err);
return;
}
if(stat.isFile())
{
const newPath = path.replace(src, build); // Replace src path with build path.
Fs.copyFileSync(path, newPath); // Copy file from old path in src to new path in build.
if(newPath.endsWith(".js")) // Check if it is javascript file.
{
obfuscate(newPath); // Obfuscate copied file in build folder.
}
}
else if(stat.isDirectory())
{
var newDir = path.replace(src, build); // Replace src path with build path.
if (!Fs.existsSync(newDir)) // Check if directory exists or not.
{
Fs.mkdirSync(newDir); // Create new directory.
}
readDirectory(path); // Further read the folder.
}
});
});
});
}
function obfuscate(filePath)
{
const content = Fs.readFileSync(filePath).toString(); // Read the files content.
var result = JavaScriptObfuscator.obfuscate(content,
{ // Config for obfuscation
compact: true, // Set true to enable minification
controlFlowFlattening: true,
target: 'browser'
}
); // Generated minified and obfuscated code
Fs.writeFileSync(filePath, result.getObfuscatedCode()); // Write obfuscted and minified code generated back to file.
}
Hurray!!! you made till end.
I hope you would have found it useful. If yes, than show some love by commenting and sharing.
Top comments (5)
Great article!
Really great code!
Thanks
Thank you so much for this
nicely done. Used it in our project. Thanks