@afterpack/webpack 0.2.2 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -4
- package/dist/index.cjs +86 -7
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +87 -8
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -28,9 +28,11 @@ copy in are left alone. If obfuscation fails, the build fails.
|
|
|
28
28
|
Subresource integrity plugins such as `webpack-subresource-integrity` are not supported: they hash
|
|
29
29
|
each chunk before AfterPack rewrites it, so the recorded hashes would not match the files you ship.
|
|
30
30
|
|
|
31
|
-
Each build writes a protection receipt
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
Each build writes a protection receipt to `.afterpack/receipts/`, one per output directory
|
|
32
|
+
(`.afterpack/receipts/dist.json` for `dist`). `.afterpack/` sits next to your project's lockfile,
|
|
33
|
+
`afterpack.json` or `.git` (failing those, its `package.json`), otherwise beside the build
|
|
34
|
+
directory, so the receipt never ships with your build. Run `npx afterpack verify dist` in your
|
|
35
|
+
deploy step to check that what you ship is what was obfuscated.
|
|
34
36
|
|
|
35
37
|
## Options
|
|
36
38
|
|
|
@@ -44,7 +46,7 @@ new AfterpackWebpackPlugin({ preset: "hard", seed: "git" });
|
|
|
44
46
|
| [`seed`][seed] | a number or string; `"git"` uses the current commit | a new random seed per build |
|
|
45
47
|
| [`identifiers.reserved`][identifiers.reserved] | names never to rename | none |
|
|
46
48
|
| [`paths.exclude`][paths.exclude] | globs for files to leave untouched | none |
|
|
47
|
-
| [`sourceMap.enabled`][sourceMap.enabled] | write source maps for the obfuscated output; off also drops the build's CSS maps | on in development when webpack emits a map
|
|
49
|
+
| [`sourceMap.enabled`][sourceMap.enabled] | write source maps for the obfuscated output; off also drops the build's CSS maps | off; on in development mode (`build.mode` or `NODE_ENV=development`) when webpack emits a map |
|
|
48
50
|
| [`protectionMap.enabled`][protectionMap.enabled] | write the Protection Map | on when `devtool` emits source maps |
|
|
49
51
|
| [`build.autorun`][build.autorun] | `false` turns AfterPack off | `true` |
|
|
50
52
|
|
package/dist/index.cjs
CHANGED
|
@@ -21,6 +21,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
21
21
|
}) : target, mod));
|
|
22
22
|
|
|
23
23
|
//#endregion
|
|
24
|
+
const node_crypto = __toESM(require("node:crypto"));
|
|
24
25
|
const node_fs = __toESM(require("node:fs"));
|
|
25
26
|
const node_path = __toESM(require("node:path"));
|
|
26
27
|
const __afterpack_core = __toESM(require("@afterpack/core"));
|
|
@@ -31,6 +32,7 @@ const PLUGIN_NAME = "AfterpackWebpackPlugin";
|
|
|
31
32
|
const EMITTED_JS_RE = /\.(?:js|mjs|cjs)$/;
|
|
32
33
|
const SOURCE_MODULE_RE = /\.(?:m?[jt]sx?)$/;
|
|
33
34
|
const CSS_MAP_RE = /\.css\.map$/;
|
|
35
|
+
const SRI_CONFLICT = "[afterpack-webpack] webpack-subresource-integrity is not compatible with AfterPack. It hashes each chunk for its <script integrity=...> before AfterPack obfuscates, so the browser would block every script, and it taps the same RealContentHash.updateHash bail hook AfterPack needs to rename obfuscated chunks. Remove the SubresourceIntegrityPlugin, or remove AfterPack.";
|
|
34
36
|
const PATHS_INCLUDE_UNSUPPORTED = "this plugin obfuscates the assets webpack's own chunks claim, in the pipeline — there is no output-directory walk for a glob to re-admit anything into. Use `npx afterpack <dir> --paths.include=...` for a disk walk, or drop the key.";
|
|
35
37
|
function isEmittedJs(name) {
|
|
36
38
|
return !name.includes(".hot-update.") && EMITTED_JS_RE.test(name);
|
|
@@ -59,11 +61,14 @@ function stripCssSourceMaps(compilation, RawSource) {
|
|
|
59
61
|
if (stripped !== css) compilation.updateAsset(name, new RawSource(stripped));
|
|
60
62
|
}
|
|
61
63
|
}
|
|
62
|
-
function
|
|
64
|
+
function chunkClaimedJsNames(compilation) {
|
|
63
65
|
const names = new Set();
|
|
64
66
|
for (const chunk of compilation.chunks) for (const name of chunk.files) if (isEmittedJs(name)) names.add(name);
|
|
67
|
+
return [...names];
|
|
68
|
+
}
|
|
69
|
+
function chunkClaimedJsAssets(compilation) {
|
|
65
70
|
const out = [];
|
|
66
|
-
for (const name of
|
|
71
|
+
for (const name of chunkClaimedJsNames(compilation)) {
|
|
67
72
|
const asset = compilation.getAsset(name);
|
|
68
73
|
if (!asset) continue;
|
|
69
74
|
const related = asset.info.related;
|
|
@@ -95,6 +100,8 @@ var AfterpackWebpackPlugin = class {
|
|
|
95
100
|
seenByBuildHooksThisCompilation = new Set();
|
|
96
101
|
captureDiagnostics = [];
|
|
97
102
|
deferredReceiptByCompilation = new WeakMap();
|
|
103
|
+
hashSalt = null;
|
|
104
|
+
warnedRealContentHash = false;
|
|
98
105
|
constructor(options = {}) {
|
|
99
106
|
const resolved = (0, __afterpack_integration_utils.resolvePluginConfig)({
|
|
100
107
|
label: PLUGIN_NAME,
|
|
@@ -106,10 +113,33 @@ var AfterpackWebpackPlugin = class {
|
|
|
106
113
|
}
|
|
107
114
|
apply(compiler) {
|
|
108
115
|
const context = compiler.options.context ?? process.cwd();
|
|
116
|
+
const sri = (compiler.options.plugins ?? []).find((plugin) => /SubresourceIntegrity/.test(plugin?.constructor?.name ?? ""));
|
|
117
|
+
if (sri) throw new Error(SRI_CONFLICT);
|
|
109
118
|
const directivesEnabled = this.settings.directives.enabled;
|
|
110
119
|
if (directivesEnabled) compiler.hooks.thisCompilation.tap(PLUGIN_NAME, () => {
|
|
111
120
|
this.seenByBuildHooksThisCompilation.clear();
|
|
112
121
|
});
|
|
122
|
+
if (this.settings.build?.autorun !== false) {
|
|
123
|
+
const devtool = compiler.options.devtool;
|
|
124
|
+
const hasBundlerSourcemap = typeof devtool === "string" && devtool.includes("source-map");
|
|
125
|
+
const prepare = async () => {
|
|
126
|
+
this.hashSalt = await (0, __afterpack_integration_utils.prepareHashSalt)({
|
|
127
|
+
seed: this.settings.seed,
|
|
128
|
+
root: context,
|
|
129
|
+
leg: compiler.outputPath,
|
|
130
|
+
localEngineVersion: await (0, __afterpack_integration_utils.readEngineVersion)({ version: __afterpack_core.version }),
|
|
131
|
+
settings: (0, __afterpack_integration_utils.saltSettings)((0, __afterpack_integration_utils.passSettings)({
|
|
132
|
+
options: this.settings,
|
|
133
|
+
engineConfig: this.engineConfig
|
|
134
|
+
}), { ...(0, __afterpack_integration_utils.reportPolicySaltBits)(process.env, this.settings.artifactOptions, hasBundlerSourcemap) }),
|
|
135
|
+
warn: (message) => console.warn(message)
|
|
136
|
+
});
|
|
137
|
+
};
|
|
138
|
+
compiler.hooks.make.tapPromise(PLUGIN_NAME, prepare);
|
|
139
|
+
compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
|
|
140
|
+
this.saltJavascriptHashes(compiler, compilation);
|
|
141
|
+
});
|
|
142
|
+
}
|
|
113
143
|
compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
|
|
114
144
|
if (directivesEnabled) {
|
|
115
145
|
const hooks = compiler.webpack.NormalModule.getCompilationHooks(compilation);
|
|
@@ -119,7 +149,7 @@ var AfterpackWebpackPlugin = class {
|
|
|
119
149
|
}
|
|
120
150
|
compilation.hooks.processAssets.tapPromise({
|
|
121
151
|
name: PLUGIN_NAME,
|
|
122
|
-
stage: compiler.webpack.Compilation.
|
|
152
|
+
stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_HASH + 1
|
|
123
153
|
}, () => this.obfuscate(compiler, compilation, context));
|
|
124
154
|
});
|
|
125
155
|
compiler.hooks.afterEmit.tapPromise(PLUGIN_NAME, async (compilation) => {
|
|
@@ -134,6 +164,56 @@ var AfterpackWebpackPlugin = class {
|
|
|
134
164
|
}
|
|
135
165
|
});
|
|
136
166
|
}
|
|
167
|
+
directiveSaltForChunk(compilation, chunk) {
|
|
168
|
+
if (!this.settings.directives.enabled || this.captured.size === 0) return "";
|
|
169
|
+
const chunkGraph = compilation.chunkGraph;
|
|
170
|
+
if (!chunkGraph) return "";
|
|
171
|
+
const resources = [];
|
|
172
|
+
for (const module$1 of chunkGraph.getChunkModulesIterable(chunk)) collectResourcesThroughConcatenatedModules(module$1, resources);
|
|
173
|
+
const parts = [];
|
|
174
|
+
for (const resource of resources) {
|
|
175
|
+
const cap = this.captured.get(resource);
|
|
176
|
+
if (cap && (cap.directives.length > 0 || cap.renameGlobals)) parts.push(JSON.stringify({
|
|
177
|
+
id: cap.id,
|
|
178
|
+
d: cap.directives,
|
|
179
|
+
g: cap.renameGlobals
|
|
180
|
+
}));
|
|
181
|
+
}
|
|
182
|
+
if (parts.length === 0) return "";
|
|
183
|
+
return (0, node_crypto.createHash)("sha256").update(parts.sort().join("\0")).digest("hex").slice(0, 16);
|
|
184
|
+
}
|
|
185
|
+
saltJavascriptHashes(compiler, compilation) {
|
|
186
|
+
const salt = () => this.hashSalt?.salt;
|
|
187
|
+
const { JavascriptModulesPlugin } = compiler.webpack.javascript;
|
|
188
|
+
JavascriptModulesPlugin.getCompilationHooks(compilation).chunkHash.tap(PLUGIN_NAME, (chunk, hash) => {
|
|
189
|
+
const value = salt();
|
|
190
|
+
if (!value) return;
|
|
191
|
+
hash.update(value);
|
|
192
|
+
const directives = this.directiveSaltForChunk(compilation, chunk);
|
|
193
|
+
if (directives) hash.update(directives);
|
|
194
|
+
});
|
|
195
|
+
const realContentHash = compiler.webpack.optimize.RealContentHashPlugin;
|
|
196
|
+
if (typeof realContentHash.getCompilationHooks !== "function") {
|
|
197
|
+
if (compiler.options.optimization?.realContentHash && !this.warnedRealContentHash) {
|
|
198
|
+
this.warnedRealContentHash = true;
|
|
199
|
+
console.warn("[afterpack-webpack] this webpack version offers no hook into realContentHash, so each obfuscated chunk keeps the name of its plain bytes. Upgrade webpack, or set `optimization.realContentHash: false`.");
|
|
200
|
+
}
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
let jsNames = null;
|
|
204
|
+
realContentHash.getCompilationHooks(compilation).updateHash.tap(PLUGIN_NAME, (content, oldHash) => {
|
|
205
|
+
const value = salt();
|
|
206
|
+
if (!value) return void 0;
|
|
207
|
+
jsNames ??= chunkClaimedJsNames(compilation);
|
|
208
|
+
if (!jsNames.some((name) => name.includes(oldHash))) return void 0;
|
|
209
|
+
const { hashFunction, hashDigest, hashSalt } = compilation.outputOptions;
|
|
210
|
+
const hash = compiler.webpack.util.createHash(hashFunction ?? "md4");
|
|
211
|
+
if (hashSalt) hash.update(hashSalt);
|
|
212
|
+
hash.update(value);
|
|
213
|
+
for (const chunk of content) hash.update(chunk);
|
|
214
|
+
return String(hash.digest(hashDigest ?? "hex")).slice(0, oldHash.length);
|
|
215
|
+
});
|
|
216
|
+
}
|
|
137
217
|
async obfuscate(compiler, compilation, context) {
|
|
138
218
|
if (this.settings.build?.autorun === false) return;
|
|
139
219
|
const startedAt = Date.now();
|
|
@@ -172,12 +252,11 @@ var AfterpackWebpackPlugin = class {
|
|
|
172
252
|
telemetry: (0, __afterpack_integration_utils.createTelemetryReporter)(),
|
|
173
253
|
label: "afterpack-webpack",
|
|
174
254
|
cwd: context,
|
|
255
|
+
resolvedSeed: this.hashSalt?.resolvedSeed,
|
|
256
|
+
cloudEngineExpectation: this.hashSalt?.engine,
|
|
175
257
|
startedAt,
|
|
176
258
|
capturedByFile: capturedByFile.size > 0 ? capturedByFile : void 0,
|
|
177
|
-
combinedProtectionMap: {
|
|
178
|
-
buildDir: outputPath,
|
|
179
|
-
afterpackDir: (0, node_path.join)(context, ".afterpack")
|
|
180
|
-
},
|
|
259
|
+
combinedProtectionMap: { buildDir: outputPath },
|
|
181
260
|
...(0, __afterpack_integration_utils.passSettings)({
|
|
182
261
|
options: this.settings,
|
|
183
262
|
engineConfig: this.engineConfig
|
package/dist/index.d.cts
CHANGED
|
@@ -10,8 +10,12 @@ declare class AfterpackWebpackPlugin {
|
|
|
10
10
|
private readonly seenByBuildHooksThisCompilation;
|
|
11
11
|
private readonly captureDiagnostics;
|
|
12
12
|
private readonly deferredReceiptByCompilation;
|
|
13
|
+
private hashSalt;
|
|
14
|
+
private warnedRealContentHash;
|
|
13
15
|
constructor(options?: AfterpackWebpackOptions);
|
|
14
16
|
apply(compiler: Compiler): void;
|
|
17
|
+
private directiveSaltForChunk;
|
|
18
|
+
private saltJavascriptHashes;
|
|
15
19
|
private obfuscate;
|
|
16
20
|
private capture;
|
|
17
21
|
private joinCaptured;
|
package/dist/index.d.ts
CHANGED
|
@@ -10,8 +10,12 @@ declare class AfterpackWebpackPlugin {
|
|
|
10
10
|
private readonly seenByBuildHooksThisCompilation;
|
|
11
11
|
private readonly captureDiagnostics;
|
|
12
12
|
private readonly deferredReceiptByCompilation;
|
|
13
|
+
private hashSalt;
|
|
14
|
+
private warnedRealContentHash;
|
|
13
15
|
constructor(options?: AfterpackWebpackOptions);
|
|
14
16
|
apply(compiler: Compiler): void;
|
|
17
|
+
private directiveSaltForChunk;
|
|
18
|
+
private saltJavascriptHashes;
|
|
15
19
|
private obfuscate;
|
|
16
20
|
private capture;
|
|
17
21
|
private joinCaptured;
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
1
2
|
import { readFileSync } from "node:fs";
|
|
2
3
|
import { basename, join, relative } from "node:path";
|
|
3
4
|
import { processBatch, version } from "@afterpack/core";
|
|
4
|
-
import { createTelemetryReporter, decodeDataUri, extractSourceMappingURL, passSettings, resolveClientIdentity, resolvePluginConfig, runObfuscationPass, scanDirectives, sourceTypeForOutputFormat, withSourceMappingURL, withoutCssSourceMappingURL, writeDeferredProtectionReceipt } from "@afterpack/integration-utils";
|
|
5
|
+
import { createTelemetryReporter, decodeDataUri, extractSourceMappingURL, passSettings, prepareHashSalt, readEngineVersion, reportPolicySaltBits, resolveClientIdentity, resolvePluginConfig, runObfuscationPass, saltSettings, scanDirectives, sourceTypeForOutputFormat, withSourceMappingURL, withoutCssSourceMappingURL, writeDeferredProtectionReceipt } from "@afterpack/integration-utils";
|
|
5
6
|
|
|
6
7
|
//#region src/index.ts
|
|
7
8
|
const PLUGIN_NAME = "AfterpackWebpackPlugin";
|
|
8
9
|
const EMITTED_JS_RE = /\.(?:js|mjs|cjs)$/;
|
|
9
10
|
const SOURCE_MODULE_RE = /\.(?:m?[jt]sx?)$/;
|
|
10
11
|
const CSS_MAP_RE = /\.css\.map$/;
|
|
12
|
+
const SRI_CONFLICT = "[afterpack-webpack] webpack-subresource-integrity is not compatible with AfterPack. It hashes each chunk for its <script integrity=...> before AfterPack obfuscates, so the browser would block every script, and it taps the same RealContentHash.updateHash bail hook AfterPack needs to rename obfuscated chunks. Remove the SubresourceIntegrityPlugin, or remove AfterPack.";
|
|
11
13
|
const PATHS_INCLUDE_UNSUPPORTED = "this plugin obfuscates the assets webpack's own chunks claim, in the pipeline — there is no output-directory walk for a glob to re-admit anything into. Use `npx afterpack <dir> --paths.include=...` for a disk walk, or drop the key.";
|
|
12
14
|
function isEmittedJs(name) {
|
|
13
15
|
return !name.includes(".hot-update.") && EMITTED_JS_RE.test(name);
|
|
@@ -36,11 +38,14 @@ function stripCssSourceMaps(compilation, RawSource) {
|
|
|
36
38
|
if (stripped !== css) compilation.updateAsset(name, new RawSource(stripped));
|
|
37
39
|
}
|
|
38
40
|
}
|
|
39
|
-
function
|
|
41
|
+
function chunkClaimedJsNames(compilation) {
|
|
40
42
|
const names = new Set();
|
|
41
43
|
for (const chunk of compilation.chunks) for (const name of chunk.files) if (isEmittedJs(name)) names.add(name);
|
|
44
|
+
return [...names];
|
|
45
|
+
}
|
|
46
|
+
function chunkClaimedJsAssets(compilation) {
|
|
42
47
|
const out = [];
|
|
43
|
-
for (const name of
|
|
48
|
+
for (const name of chunkClaimedJsNames(compilation)) {
|
|
44
49
|
const asset = compilation.getAsset(name);
|
|
45
50
|
if (!asset) continue;
|
|
46
51
|
const related = asset.info.related;
|
|
@@ -72,6 +77,8 @@ var AfterpackWebpackPlugin = class {
|
|
|
72
77
|
seenByBuildHooksThisCompilation = new Set();
|
|
73
78
|
captureDiagnostics = [];
|
|
74
79
|
deferredReceiptByCompilation = new WeakMap();
|
|
80
|
+
hashSalt = null;
|
|
81
|
+
warnedRealContentHash = false;
|
|
75
82
|
constructor(options = {}) {
|
|
76
83
|
const resolved = resolvePluginConfig({
|
|
77
84
|
label: PLUGIN_NAME,
|
|
@@ -83,10 +90,33 @@ var AfterpackWebpackPlugin = class {
|
|
|
83
90
|
}
|
|
84
91
|
apply(compiler) {
|
|
85
92
|
const context = compiler.options.context ?? process.cwd();
|
|
93
|
+
const sri = (compiler.options.plugins ?? []).find((plugin) => /SubresourceIntegrity/.test(plugin?.constructor?.name ?? ""));
|
|
94
|
+
if (sri) throw new Error(SRI_CONFLICT);
|
|
86
95
|
const directivesEnabled = this.settings.directives.enabled;
|
|
87
96
|
if (directivesEnabled) compiler.hooks.thisCompilation.tap(PLUGIN_NAME, () => {
|
|
88
97
|
this.seenByBuildHooksThisCompilation.clear();
|
|
89
98
|
});
|
|
99
|
+
if (this.settings.build?.autorun !== false) {
|
|
100
|
+
const devtool = compiler.options.devtool;
|
|
101
|
+
const hasBundlerSourcemap = typeof devtool === "string" && devtool.includes("source-map");
|
|
102
|
+
const prepare = async () => {
|
|
103
|
+
this.hashSalt = await prepareHashSalt({
|
|
104
|
+
seed: this.settings.seed,
|
|
105
|
+
root: context,
|
|
106
|
+
leg: compiler.outputPath,
|
|
107
|
+
localEngineVersion: await readEngineVersion({ version }),
|
|
108
|
+
settings: saltSettings(passSettings({
|
|
109
|
+
options: this.settings,
|
|
110
|
+
engineConfig: this.engineConfig
|
|
111
|
+
}), { ...reportPolicySaltBits(process.env, this.settings.artifactOptions, hasBundlerSourcemap) }),
|
|
112
|
+
warn: (message) => console.warn(message)
|
|
113
|
+
});
|
|
114
|
+
};
|
|
115
|
+
compiler.hooks.make.tapPromise(PLUGIN_NAME, prepare);
|
|
116
|
+
compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
|
|
117
|
+
this.saltJavascriptHashes(compiler, compilation);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
90
120
|
compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
|
|
91
121
|
if (directivesEnabled) {
|
|
92
122
|
const hooks = compiler.webpack.NormalModule.getCompilationHooks(compilation);
|
|
@@ -96,7 +126,7 @@ var AfterpackWebpackPlugin = class {
|
|
|
96
126
|
}
|
|
97
127
|
compilation.hooks.processAssets.tapPromise({
|
|
98
128
|
name: PLUGIN_NAME,
|
|
99
|
-
stage: compiler.webpack.Compilation.
|
|
129
|
+
stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_HASH + 1
|
|
100
130
|
}, () => this.obfuscate(compiler, compilation, context));
|
|
101
131
|
});
|
|
102
132
|
compiler.hooks.afterEmit.tapPromise(PLUGIN_NAME, async (compilation) => {
|
|
@@ -111,6 +141,56 @@ var AfterpackWebpackPlugin = class {
|
|
|
111
141
|
}
|
|
112
142
|
});
|
|
113
143
|
}
|
|
144
|
+
directiveSaltForChunk(compilation, chunk) {
|
|
145
|
+
if (!this.settings.directives.enabled || this.captured.size === 0) return "";
|
|
146
|
+
const chunkGraph = compilation.chunkGraph;
|
|
147
|
+
if (!chunkGraph) return "";
|
|
148
|
+
const resources = [];
|
|
149
|
+
for (const module of chunkGraph.getChunkModulesIterable(chunk)) collectResourcesThroughConcatenatedModules(module, resources);
|
|
150
|
+
const parts = [];
|
|
151
|
+
for (const resource of resources) {
|
|
152
|
+
const cap = this.captured.get(resource);
|
|
153
|
+
if (cap && (cap.directives.length > 0 || cap.renameGlobals)) parts.push(JSON.stringify({
|
|
154
|
+
id: cap.id,
|
|
155
|
+
d: cap.directives,
|
|
156
|
+
g: cap.renameGlobals
|
|
157
|
+
}));
|
|
158
|
+
}
|
|
159
|
+
if (parts.length === 0) return "";
|
|
160
|
+
return createHash("sha256").update(parts.sort().join("\0")).digest("hex").slice(0, 16);
|
|
161
|
+
}
|
|
162
|
+
saltJavascriptHashes(compiler, compilation) {
|
|
163
|
+
const salt = () => this.hashSalt?.salt;
|
|
164
|
+
const { JavascriptModulesPlugin } = compiler.webpack.javascript;
|
|
165
|
+
JavascriptModulesPlugin.getCompilationHooks(compilation).chunkHash.tap(PLUGIN_NAME, (chunk, hash) => {
|
|
166
|
+
const value = salt();
|
|
167
|
+
if (!value) return;
|
|
168
|
+
hash.update(value);
|
|
169
|
+
const directives = this.directiveSaltForChunk(compilation, chunk);
|
|
170
|
+
if (directives) hash.update(directives);
|
|
171
|
+
});
|
|
172
|
+
const realContentHash = compiler.webpack.optimize.RealContentHashPlugin;
|
|
173
|
+
if (typeof realContentHash.getCompilationHooks !== "function") {
|
|
174
|
+
if (compiler.options.optimization?.realContentHash && !this.warnedRealContentHash) {
|
|
175
|
+
this.warnedRealContentHash = true;
|
|
176
|
+
console.warn("[afterpack-webpack] this webpack version offers no hook into realContentHash, so each obfuscated chunk keeps the name of its plain bytes. Upgrade webpack, or set `optimization.realContentHash: false`.");
|
|
177
|
+
}
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
let jsNames = null;
|
|
181
|
+
realContentHash.getCompilationHooks(compilation).updateHash.tap(PLUGIN_NAME, (content, oldHash) => {
|
|
182
|
+
const value = salt();
|
|
183
|
+
if (!value) return void 0;
|
|
184
|
+
jsNames ??= chunkClaimedJsNames(compilation);
|
|
185
|
+
if (!jsNames.some((name) => name.includes(oldHash))) return void 0;
|
|
186
|
+
const { hashFunction, hashDigest, hashSalt } = compilation.outputOptions;
|
|
187
|
+
const hash = compiler.webpack.util.createHash(hashFunction ?? "md4");
|
|
188
|
+
if (hashSalt) hash.update(hashSalt);
|
|
189
|
+
hash.update(value);
|
|
190
|
+
for (const chunk of content) hash.update(chunk);
|
|
191
|
+
return String(hash.digest(hashDigest ?? "hex")).slice(0, oldHash.length);
|
|
192
|
+
});
|
|
193
|
+
}
|
|
114
194
|
async obfuscate(compiler, compilation, context) {
|
|
115
195
|
if (this.settings.build?.autorun === false) return;
|
|
116
196
|
const startedAt = Date.now();
|
|
@@ -149,12 +229,11 @@ var AfterpackWebpackPlugin = class {
|
|
|
149
229
|
telemetry: createTelemetryReporter(),
|
|
150
230
|
label: "afterpack-webpack",
|
|
151
231
|
cwd: context,
|
|
232
|
+
resolvedSeed: this.hashSalt?.resolvedSeed,
|
|
233
|
+
cloudEngineExpectation: this.hashSalt?.engine,
|
|
152
234
|
startedAt,
|
|
153
235
|
capturedByFile: capturedByFile.size > 0 ? capturedByFile : void 0,
|
|
154
|
-
combinedProtectionMap: {
|
|
155
|
-
buildDir: outputPath,
|
|
156
|
-
afterpackDir: join(context, ".afterpack")
|
|
157
|
-
},
|
|
236
|
+
combinedProtectionMap: { buildDir: outputPath },
|
|
158
237
|
...passSettings({
|
|
159
238
|
options: this.settings,
|
|
160
239
|
engineConfig: this.engineConfig
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@afterpack/webpack",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "webpack plugin for AfterPack: obfuscate your production JavaScript during the webpack build",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
"webpack": "^5.0.0"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@afterpack/core": "~0.2.
|
|
32
|
-
"@afterpack/integration-utils": "0.2.
|
|
31
|
+
"@afterpack/core": "~0.2.5",
|
|
32
|
+
"@afterpack/integration-utils": "0.2.4"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@biomejs/biome": "2.4.4",
|