webpack-obfuscator
Version:
javascript-obfuscator plugin for Webpack@5
131 lines (130 loc) • 6.96 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.WebpackObfuscatorPlugin = void 0;
const webpack_1 = require("webpack");
const javascript_obfuscator_1 = __importDefault(require("javascript-obfuscator"));
const multimatch_1 = __importDefault(require("multimatch"));
const transferSourceMap = require("multi-stage-sourcemap").transfer;
class WebpackObfuscatorPlugin {
constructor(options = {}, excludes, proApiConfig, onProgress) {
this.options = options;
this.excludes = [];
this.excludes = this.excludes.concat(excludes || []);
this.proApiConfig = proApiConfig;
this.onProgress = onProgress;
}
apply(compiler) {
const isDevServer = process.argv.find(v => v.includes('webpack-dev-server'));
if (isDevServer) {
console.info('JavascriptObfuscator is disabled on webpack-dev-server as the reloading scripts ', 'and the obfuscator can interfere with each other and break the build');
return;
}
const pluginName = this.constructor.name;
compiler.hooks.compilation.tap(pluginName, (compilation) => {
compilation.hooks.processAssets.tapPromise({
name: 'WebpackObfuscator',
stage: webpack_1.Compilation.PROCESS_ASSETS_STAGE_DEV_TOOLING
}, (assets) => __awaiter(this, void 0, void 0, function* () {
let identifiersPrefixCounter = 0;
const sourcemapOutput = {};
const filesToProcess = [];
compilation.chunks.forEach(chunk => {
chunk.files.forEach((fileName) => {
const isSourceMap = Boolean(this.options.sourceMap) && fileName.toLowerCase().endsWith('.map');
filesToProcess.push({ chunk, fileName, isSourceMap });
});
});
const jsFiles = filesToProcess.filter(f => !f.isSourceMap);
const mapFiles = filesToProcess.filter(f => f.isSourceMap);
for (const { fileName } of jsFiles) {
const isValidExtension = WebpackObfuscatorPlugin
.allowedExtensions
.some((extension) => fileName.toLowerCase().endsWith(extension));
if (!isValidExtension || this.shouldExclude(fileName)) {
continue;
}
const asset = compilation.assets[fileName];
const { inputSource, inputSourceMap } = this.extractSourceAndSourceMap(asset);
const { obfuscatedSource, obfuscationSourceMap } = yield this.obfuscate(inputSource, fileName, identifiersPrefixCounter);
if (this.options.sourceMap && inputSourceMap) {
sourcemapOutput[fileName] = obfuscationSourceMap;
const transferredSourceMap = transferSourceMap({
fromSourceMap: obfuscationSourceMap,
toSourceMap: inputSourceMap
});
const finalSourcemap = JSON.parse(transferredSourceMap);
assets[fileName] = new webpack_1.sources.SourceMapSource(obfuscatedSource, fileName, finalSourcemap);
}
else {
assets[fileName] = new webpack_1.sources.RawSource(obfuscatedSource, false);
}
identifiersPrefixCounter++;
}
for (const { fileName } of mapFiles) {
let srcName = fileName.toLowerCase().substr(0, fileName.length - 4);
if (!this.shouldExclude(srcName)) {
const transferredSourceMap = transferSourceMap({
fromSourceMap: sourcemapOutput[srcName],
toSourceMap: compilation.assets[fileName].source()
});
const finalSourcemap = JSON.parse(transferredSourceMap);
assets[fileName] = new webpack_1.sources.RawSource(JSON.stringify(finalSourcemap), false);
}
}
}));
});
}
shouldExclude(filePath) {
return (0, multimatch_1.default)(filePath, this.excludes).length > 0;
}
extractSourceAndSourceMap(asset) {
if (asset.sourceAndMap) {
const { source, map } = asset.sourceAndMap();
return { inputSource: source, inputSourceMap: map };
}
else {
return {
inputSource: asset.source(),
inputSourceMap: asset.map()
};
}
}
obfuscate(javascript, fileName, identifiersPrefixCounter) {
return __awaiter(this, void 0, void 0, function* () {
const obfuscatorOptions = Object.assign({ identifiersPrefix: `${WebpackObfuscatorPlugin.baseIdentifiersPrefix}${identifiersPrefixCounter}`, inputFileName: fileName, sourceMapMode: 'separate', sourceMapFileName: fileName + '.map' }, this.options);
if (this.proApiConfig) {
const obfuscationResult = yield javascript_obfuscator_1.default.obfuscatePro(javascript, obfuscatorOptions, this.proApiConfig, this.onProgress);
return {
obfuscatedSource: obfuscationResult.getObfuscatedCode(),
obfuscationSourceMap: obfuscationResult.getSourceMap()
};
}
else {
const obfuscationResult = javascript_obfuscator_1.default.obfuscate(javascript, obfuscatorOptions);
return {
obfuscatedSource: obfuscationResult.getObfuscatedCode(),
obfuscationSourceMap: obfuscationResult.getSourceMap()
};
}
});
}
}
exports.WebpackObfuscatorPlugin = WebpackObfuscatorPlugin;
WebpackObfuscatorPlugin.loader = require.resolve('../loader');
WebpackObfuscatorPlugin.allowedExtensions = [
'.js',
'.mjs'
];
WebpackObfuscatorPlugin.baseIdentifiersPrefix = 'a';