-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathplugin.ts
More file actions
130 lines (101 loc) · 4.62 KB
/
Copy pathplugin.ts
File metadata and controls
130 lines (101 loc) · 4.62 KB
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import * as esbuild from 'esbuild';
import * as JsObf from 'javascript-obfuscator';
import fs from 'fs';
import path from 'path';
import type { JSObfuscatorOptions } from '../types/JSObfuscatorOptions';
import { ValidateOptions } from './optionValidator';
import { CreateLogger } from '../logging';
type FinalizedFiles = { fileName: string; outputCode: string }[];
async function ObfuscateFile(
pluginOptions: JSObfuscatorOptions,
file: esbuild.OutputFile,
): Promise<string> {
const logger = CreateLogger(pluginOptions);
const originalCode = new TextDecoder().decode(file.contents);
if (!file.path.endsWith('.js')) {
logger('file does not end with .js, skipping obfuscation: ', file.path);
return originalCode;
}
if (pluginOptions.VMProtection?.Enabled) {
const { ApiKey, Version } = pluginOptions.VMProtection;
logger('obfuscating with VM Protection ... ');
const proApiOptions: JsObf.IProApiConfig = {
apiToken: ApiKey! /* must exist because of optionValidator */,
};
if (Version) {
Reflect.set(proApiOptions, 'version', Version);
}
const obfuscateResult = await JsObf.obfuscatePro(
originalCode,
pluginOptions.ObfuscatorOptions,
proApiOptions,
logger,
);
logger('obfuscation with VM Protection completed for file: ', file.path);
return obfuscateResult.getObfuscatedCode().toString();
}
logger('obfuscating with no VM protection...');
const obfuscateResult = JsObf.obfuscate(originalCode, pluginOptions.ObfuscatorOptions);
logger('obfuscation completed for file: ', file.path);
return obfuscateResult.getObfuscatedCode().toString();
}
export function JSObfuscatorPlugin(options: JSObfuscatorOptions) {
const log = CreateLogger(options);
log('JSObfuscatorPlugin initialized with options:', options);
const [isValid, errorMsg] = ValidateOptions(options);
log('isValid: ', isValid, ' errorMsg: ', errorMsg);
if (!isValid) {
throw new Error(`Invalid JSObfuscatorPlugin options: ${errorMsg || 'no error message provided'}`);
}
log('creating plugin');
return {
name: 'esbuild-javascript-obfuscator',
setup(build) {
if (build.initialOptions.write || build.initialOptions.write === undefined) {
throw new Error('esbuild-javascript-obfuscator plugin requires write: false in build options');
}
build.onEnd(async ({ errors, outputFiles }) => {
if (errors.length) {
log('build completed with errors, skipping obfuscation (errors: %f)', errors.length);
return;
}
if (!outputFiles) {
log('No output files found, skipping obfuscation');
return;
}
/* keep this here: on `watch` modes, this can cause a memory leak if not placed in this certain way.*/
const finalized: FinalizedFiles = [];
for (const file of outputFiles) {
const fileName = path.basename(file.path);
const shouldObfuscate =
options.ObfuscateAllFiles || (options.ObfuscateFilesWhitelist?.includes(fileName) ?? false);
if (shouldObfuscate && file.path.endsWith('.js')) {
try {
const outputCode = await ObfuscateFile(options, file);
/* write obfuscated output */
finalized.push({ fileName: file.path, outputCode });
} catch (err) {
log('failed to obfuscate file: ', file.path, err);
/* it failed, so just write the original file to the output */
finalized.push({
fileName: file.path,
outputCode: new TextDecoder().decode(file.contents),
});
}
} else {
/* should not obfuscate, write orig file. */
finalized.push({
fileName: file.path,
outputCode: new TextDecoder().decode(file.contents),
});
}
}
/* write pass */
for (const outputFile of finalized) {
fs.mkdirSync(path.dirname(outputFile.fileName), { recursive: true });
fs.writeFileSync(outputFile.fileName, outputFile.outputCode);
}
});
},
} as esbuild.Plugin;
}