Writing simple obfuscation and minification system

zicsus

Himanshu Mishra

Posted on September 9, 2019

Writing simple obfuscation and minification system

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.

Thanks for reading :)
💖 💪 🙅 🚩
zicsus
Himanshu Mishra

Posted on September 9, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related