forked from javascript-obfuscator/webpack-obfuscator
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.ts
106 lines (90 loc) · 3.79 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
"use strict";
import { Compiler, compilation } from 'webpack';
import JavaScriptObfuscator, { ObfuscatorOptions } from 'javascript-obfuscator';
import { RawSource, SourceMapSource } from 'webpack-sources';
import multimatch from 'multimatch';
import { RawSourceMap } from 'source-map';
const transferSourceMap = require("multi-stage-sourcemap").transfer;
class WebpackObfuscator {
/**
* @type {string}
*/
private static readonly baseIdentifiersPrefix: string = 'a';
public excludes: string[] = [];
constructor(
public options: ObfuscatorOptions = {},
excludes?: string | string[]
) {
this.excludes = this.excludes.concat(excludes || []);
}
public apply(compiler: Compiler): void {
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.emit.tap(pluginName, (compilation: compilation.Compilation) => {
let identifiersPrefixCounter: number = 0;
compilation.chunks.forEach(chunk => {
chunk.files.forEach((fileName: string) => {
if (!fileName.toLowerCase().endsWith('.js') || this.shouldExclude(fileName)) {
return;
}
const asset = compilation.assets[fileName]
const { inputSource, inputSourceMap } = this.extractSourceAndSourceMap(asset);
const { obfuscatedSource, obfuscationSourceMap } = this.obfuscate(inputSource, identifiersPrefixCounter);
if (this.options.sourceMap && inputSourceMap) {
const transferredSourceMap = transferSourceMap({
fromSourceMap: obfuscationSourceMap,
toSourceMap: inputSourceMap
});
compilation.assets[fileName] = new SourceMapSource(
obfuscatedSource,
fileName,
transferredSourceMap,
inputSource,
inputSourceMap
);
} else {
compilation.assets[fileName] = new RawSource(obfuscatedSource);
}
identifiersPrefixCounter++;
});
});
});
}
private shouldExclude(filePath: string): boolean {
return multimatch(filePath, this.excludes).length > 0
}
private extractSourceAndSourceMap(asset: any): { inputSource: string, inputSourceMap: RawSourceMap } {
if (asset.sourceAndMap) {
const { source, map } = asset.sourceAndMap();
return { inputSource: source, inputSourceMap: map };
} else {
return {
inputSource: asset.source(),
inputSourceMap: asset.map()
}
}
}
private obfuscate(
javascript: string,
identifiersPrefixCounter: number
): { obfuscatedSource: string, obfuscationSourceMap: string } {
const obfuscationResult = JavaScriptObfuscator.obfuscate(
javascript,
{
identifiersPrefix: `${WebpackObfuscator.baseIdentifiersPrefix}${identifiersPrefixCounter}`,
...this.options
}
);
return {
obfuscatedSource: obfuscationResult.getObfuscatedCode(),
obfuscationSourceMap: obfuscationResult.getSourceMap()
}
}
}
export = WebpackObfuscator;