Obfuscation and crypting assets in the Cocos Creator

Obfuscation and crypting assets in the Cocos Creator
0.0 0

#1

Hi all!
My question is very simple.
How can I protect (obfuscate, crypt) my js scripts and other assets in Cocos Creator?
Can I do that today, or do you schedule this feature in next releases?


#2

+1

How to customize cocos creator build process to add google closure compiler obfuscation?


#3

We will add this feature in the near future (October).

Thanks for your feedback!


#4

Any progress on the feature? A lot of people might be interested in it since there isn’t much else to do about protecting the js source code.


#5

any update please?


#6

Another thing that would help with the obfuscation would be if scripts that are marked as plugins are all placed into 1 js file like all the other scripts, so that there are fewer requests on the web platform and also this way there won’t be names of the scripts that could lead to what the script does.


#7

Hi guys, for those of you trying to obfuscate your code (Cocos creator 1.4+ already does some sort of minifying), I’ve come up with a small solution using nodejs. The code is kind of a mess but it’s working fine on my project.

I’m doing three extra steps:

  • Listing my public properties that I know that can be safely obfuscated.
  • Calling mangle-props to obfuscate all private properties.
  • Listing my project requires to obfuscate file names.

I will consider that you are already familiar with nodejs and won’t go in any details on how to install/run this.
This code should be able to run by simply changing the options listed on the beginning of the builder.js file.

Files

package.json

{
  "name": "project-builder",
  "version": "0.0.1",
  "devDependencies": {
    "mangle-props": "0.0.1"
  }
}

builder.js:

var mangleOptions = {
    // Regex used to find our private properties. Currently matches any property starting with underscore
    regex: '^_',

    // Prefix added to the properties on our propertyList before mangling. 
    // Try to avoid a single underscore since it may conflict with an existing private property.
    // The prefix won't affect the output in any way since the property will be mangled as a private property
    propertyPrefix: '__',

    // Path to your project build
    path: 'C:/project/build/web-desktop/src/',

    // Your compiled script name
    file: 'project.js',

    // Path to your output
    outputPath: 'C:/project/build/web-desktop/src/',

    // Name to your outputfile
    // You can have the same file/path if you want to replace your original file
    outputFile: 'project-mangled.js'
};

// If you want to mangle even further, you can populate this list public properties that you want to mangle.
// Keep in mind that you won't have external access to the listed properties here and any properties that match this list will be mangled,
// so take care with functions with names such as: setTimeout, addEventListener, removeEventListener.
var propertyList = [    
    // PlayerMenuUI
    'setPlayer', 'hasPlayer'
];

// List of externs used on the project. We use this list to mangle our requires and classes names
// You can get this by simply copying the last array shown on your src/project.js build output
var externList = [
    "PlayerMenuUI", "ColorConstants"
];

// Below this point is our code. You don't need to edit anything else.

var mangleData = function (data) {
    // We rename all cocos functions to avoid problems in case you are using underscore on private properties
    var ret = data.replace(new RegExp('cc._', 'gi'), 'cc.tmp');
    
    ret = require('mangle-props')(ret, mangleOptions.regex);
    
    // Renaming cocos functions back before returning.
    // mangle-props returns an object instead of a string so we simply prepend an string to convert it to a string
    return ('' + ret).replace(new RegExp('cc.tmp', 'gi'), 'cc._');
};

var replaceProperties = function (data, list) {
    for (var i = 0; i < list.length; i++) {
        data = data.replace(new RegExp(list[i], 'gi'), mangleOptions.propertyPrefix + list[i]);
    }
    return data;
};

//Source: http://stackoverflow.com/questions/2256607/how-to-get-the-next-letter-of-the-alphabet-in-javascript
var getNextKey = function(key) {
  if (key === 'Z' || key === 'z') {
    return String.fromCharCode(key.charCodeAt() - 25) + String.fromCharCode(key.charCodeAt() - 25); // AA or aa
  } else {
    var lastChar = key.slice(-1);
    var sub = key.slice(0, -1);
    if (lastChar === 'Z' || lastChar === 'z') {
      // If a string of length > 1 ends in Z/z,
      // increment the string (excluding the last Z/z) recursively,
      // and append A/a (depending on casing) to it
      return getNextKey(sub) + String.fromCharCode(lastChar.charCodeAt() - 25);
    } else {
      // (take till last char) append with (increment last char)
      return sub + String.fromCharCode(lastChar.charCodeAt() + 1);
    }
  }
  return key;
};

var replaceExterns = function (data, list) {
    var key = 'a';
    for (var i = 0; i < list.length; i++) {
        data = data.replace(new RegExp(list[i], 'gi'), key);
        key = getNextKey(key);
    }
    return data;    
}

var devMinifier = function () {
    var fs = require('fs');

    fs.readFile(mangleOptions.path + mangleOptions.file, 'utf8', function(err, data) {
        if (err !== null) {
            console.log(err);
            return;
        }

        data = replaceProperties(data, propertyList);
        data = replaceExterns(data, externList);
        data = mangleData(data);

        fs.writeFile(mangleOptions.outputPath + mangleOptions.outputFile, data, 'utf8', function(err) {
            if(err) {
                console.log(err);
            } else {
                console.log('Mangled ' + mangleOptions.file);
            }
        });
    });
};

devMinifier();

Sample output

Note: The example that I have used does not have any private properties but they would be obfuscated automatically.

Cocos creator output

PlayerMenuUI: [function(e, t, a) {
    "use strict";
    cc._RFpush(t, "f952fMALCBGI4WyMT0hkFsy", "PlayerMenuUI");
    var n = e("ColorConstants");
    cc.Class({
        "extends": cc.Component,
        properties: {
            label: {
                "default": null,
                type: cc.Label
            },
            player: null
        },
        setPlayer: function(e) {
            this.player = e,
            null !== e.data && "undefined" !== e.data.slot && (this.node.color = n.list[e.data.slot]),
            this.label.string = e.state
        },
        hasPlayer: function(e) {
            return this.player.id === e.id
        }
    }),
    cc._RFpop()
}

builder.js output

t: [function(e, t, a) {
    "use strict";
    cc._RFpush(t, "f952fMALCBGI4WyMT0hkFsy", "t");
    var n = e("d");
    cc.Class({
        "extends": cc.Component,
        properties: {
            label: {
                "default": null,
                type: cc.Label
            },
            player: null
        },
        aM: function(e) {
            this.player = e,
            null !== e.data && "undefined" !== e.data.slot && (this.node.color = n.list[e.data.slot]),
            this.label.string = e.state
        },
        aV: function(e) {
            return this.player.id === e.id
        }
    }),
    cc._RFpop()
}

Sources

mangle-props package: https://www.npmjs.com/package/mangle-props
getNextKey method: http://stackoverflow.com/questions/2256607/how-to-get-the-next-letter-of-the-alphabet-in-javascript


#8

any updates on this ?