cordova-plugin-crypt-file
Version:
This plugin to encrypt/decrypt the source files.
170 lines (136 loc) • 7.74 kB
JavaScript
module.exports = function(context) {
var path = context.requireCordovaModule('path'),
fs = context.requireCordovaModule('fs'),
crypto = context.requireCordovaModule('crypto'),
Q = context.requireCordovaModule('q'),
cordova_util = context.requireCordovaModule('cordova-lib/src/cordova/util'),
platforms = context.requireCordovaModule('cordova-lib/src/platforms/platforms'),
Parser = context.requireCordovaModule('cordova-lib/src/cordova/metadata/parser'),
ParserHelper = context.requireCordovaModule('cordova-lib/src/cordova/metadata/parserhelper/ParserHelper'),
ConfigParser = context.requireCordovaModule('cordova-common').ConfigParser;
var deferral = new Q.defer();
var projectRoot = cordova_util.cdProjectRoot();
var key = crypto.randomBytes(24).toString('base64');
var iv = crypto.randomBytes(12).toString('base64');
console.log('key=' + key + ', iv=' + iv)
var targetFiles = loadCryptFileTargets();
context.opts.platforms.filter(function(platform) {
var pluginInfo = context.opts.plugin.pluginInfo;
return pluginInfo.getPlatformsArray().indexOf(platform) > -1;
}).forEach(function(platform) {
var platformPath = path.join(projectRoot, 'platforms', platform);
var platformApi = platforms.getPlatformApi(platform, platformPath);
var platformInfo = platformApi.getPlatformInfo();
var wwwDir = platformInfo.locations.www;
findCryptFiles(wwwDir).filter(function(file) {
return isCryptFile(file.replace(wwwDir, ''));
}).forEach(function(file) {
var content = fs.readFileSync(file, 'utf-8');
fs.writeFileSync(file, encryptData(content, key, iv), 'utf-8');
console.log('encrypt: ' + file);
});
if (platform == 'ios') {
var pluginDir;
try {
var ios_parser = context.requireCordovaModule('cordova-lib/src/cordova/metadata/ios_parser'),
iosParser = new ios_parser(platformPath);
pluginDir = path.join(iosParser.cordovaproj, 'Plugins', context.opts.plugin.id);
} catch (err) {
var xcodeproj_dir = fs.readdirSync(platformPath).filter(function(e) { return e.match(/\.xcodeproj$/i); })[0],
xcodeproj = path.join(platformPath, xcodeproj_dir),
originalName = xcodeproj.substring(xcodeproj.lastIndexOf(path.sep)+1, xcodeproj.indexOf('.xcodeproj')),
cordovaproj = path.join(platformPath, originalName);
pluginDir = path.join(cordovaproj, 'Plugins', context.opts.plugin.id);
}
replaceCryptKey_ios(pluginDir, key, iv);
} else if (platform == 'android') {
var pluginDir = path.join(platformPath, 'src');
replaceCryptKey_android(pluginDir, key, iv);
var cfg = new ConfigParser(platformInfo.projectConfig.path);
cfg.doc.getroot().getchildren().filter(function(child, idx, arr) {
return (child.tag == 'content');
}).forEach(function(child) {
child.attrib.src = '/+++/' + child.attrib.src;
});
cfg.write();
}
});
deferral.resolve();
return deferral.promise;
function findCryptFiles(dir) {
var fileList = [];
var list = fs.readdirSync(dir);
list.forEach(function(file) {
fileList.push(path.join(dir, file));
});
// sub dir
list.filter(function(file) {
return fs.statSync(path.join(dir, file)).isDirectory();
}).forEach(function(file) {
var subDir = path.join(dir, file)
var subFileList = findCryptFiles(subDir);
fileList = fileList.concat(subFileList);
});
return fileList;
}
function loadCryptFileTargets() {
var xmlHelpers = context.requireCordovaModule('cordova-common').xmlHelpers;
var pluginXml = path.join(context.opts.plugin.dir, 'plugin.xml');
var include = [];
var exclude = [];
var doc = xmlHelpers.parseElementtreeSync(pluginXml);
var cryptfiles = doc.findall('cryptfiles');
if (cryptfiles.length > 0) {
cryptfiles[0]._children.forEach(function(elm) {
elm._children.filter(function(celm) {
return celm.tag == 'file' && celm.attrib.regex && celm.attrib.regex.trim().length > 0;
}).forEach(function(celm) {
if (elm.tag == 'include') {
include.push(celm.attrib.regex.trim());
} else if (elm.tag == 'exclude') {
exclude.push(celm.attrib.regex.trim());
}
});
})
}
return {'include': include, 'exclude': exclude};
}
function isCryptFile(file) {
if (!targetFiles.include.some(function(regexStr) { return new RegExp(regexStr).test(file); })) {
return false;
}
if (targetFiles.exclude.some(function(regexStr) { return new RegExp(regexStr).test(file); })) {
return false;
}
return true;
}
function encryptData(input, key, iv) {
var cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
var encrypted = cipher.update(input, 'utf8', 'base64') + cipher.final('base64');
return encrypted;
}
function replaceCryptKey_ios(pluginDir, key, iv) {
var sourceFile = path.join(pluginDir, 'CDVCryptURLProtocol.m');
var content = fs.readFileSync(sourceFile, 'utf-8');
var includeArrStr = targetFiles.include.map(function(pattern) { return '@"' + pattern.replace('\\', '\\\\') + '"'; }).join(', ');
var excludeArrStr = targetFiles.exclude.map(function(pattern) { return '@"' + pattern.replace('\\', '\\\\') + '"'; }).join(', ');
content = content.replace(/kCryptKey = @".*";/, 'kCryptKey = @"' + key + '";')
.replace(/kCryptIv = @".*";/, 'kCryptIv = @"' + iv + '";')
.replace(/kIncludeFiles\[\] = {.*};/, 'kIncludeFiles\[\] = { ' + includeArrStr + ' };')
.replace(/kExcludeFiles\[\] = {.*};/, 'kExcludeFiles\[\] = { ' + excludeArrStr + ' };')
.replace(/kIncludeFileLength = [0-9]+;/, 'kIncludeFileLength = ' + targetFiles.include.length + ';')
.replace(/kExcludeFileLength = [0-9]+;/, 'kExcludeFileLength = ' + targetFiles.exclude.length + ';');
fs.writeFileSync(sourceFile, content, 'utf-8');
}
function replaceCryptKey_android(pluginDir, key, iv) {
var sourceFile = path.join(pluginDir, 'com/tkyaji/cordova/DecryptResource.java');
var content = fs.readFileSync(sourceFile, 'utf-8');
var includeArrStr = targetFiles.include.map(function(pattern) { return '"' + pattern.replace('\\', '\\\\') + '"'; }).join(', ');
var excludeArrStr = targetFiles.exclude.map(function(pattern) { return '"' + pattern.replace('\\', '\\\\') + '"'; }).join(', ');
content = content.replace(/CRYPT_KEY = ".*";/, 'CRYPT_KEY = "' + key + '";')
.replace(/CRYPT_IV = ".*";/, 'CRYPT_IV = "' + iv + '";')
.replace(/INCLUDE_FILES = new String\[\] {.*};/, 'INCLUDE_FILES = new String[] { ' + includeArrStr + ' };')
.replace(/EXCLUDE_FILES = new String\[\] {.*};/, 'EXCLUDE_FILES = new String[] { ' + excludeArrStr + ' };');
fs.writeFileSync(sourceFile, content, 'utf-8');
}
}