javascript-obfuscator 5.5.1 → 5.7.0
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/CHANGELOG.md +9 -0
- package/README.md +254 -2
- package/dist/index.browser.js +3 -3
- package/dist/index.browser.js.map +1 -1
- package/dist/index.cli.js +1 -1
- package/dist/index.cli.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/typings/src/interfaces/options/IOptions.d.ts +1 -0
- package/typings/src/options/Options.d.ts +1 -0
- package/typings/src/utils/AdvertisementUtils.d.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
Change Log
|
|
2
2
|
|
|
3
|
+
v5.7.0
|
|
4
|
+
---
|
|
5
|
+
* **New option:** `advertisement` allows to control the display of the JavaScript Obfuscator Pro advertisement message in the console. Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1448
|
|
6
|
+
|
|
7
|
+
v5.6.0
|
|
8
|
+
---
|
|
9
|
+
* Pro API: `obfuscatePro` now fall back to the basic local obfuscation API when no Pro feature (`vmObfuscation` or `parseHtml`) is enabled, instead of throwing an `ApiError`
|
|
10
|
+
* Improved `stringArrayEncoding` runtime performance
|
|
11
|
+
|
|
3
12
|
v5.5.1
|
|
4
13
|
---
|
|
5
14
|
* Fixed leading whitespace of the source code being stripped without being reflected in the source map, shifting all `sourcesContent` and original position mappings. Fixes https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1437
|
package/README.md
CHANGED
|
@@ -348,7 +348,7 @@ console.log(result.getObfuscatedCode());
|
|
|
348
348
|
**Parameters:**
|
|
349
349
|
|
|
350
350
|
* `sourceCode` (`string`) – source code to obfuscate
|
|
351
|
-
* `options` (`Object`) – obfuscation options.
|
|
351
|
+
* `options` (`Object`) – obfuscation options. To use the Pro API, include at least one Pro feature: `vmObfuscation: true` or `parseHtml: true`. When no Pro feature is enabled, `obfuscatePro` falls back to the basic (local) obfuscation API.
|
|
352
352
|
* `apiConfig` (`Object`) – Pro API configuration:
|
|
353
353
|
* `apiToken` (`string`, required) – your API token from obfuscator.io
|
|
354
354
|
* `timeout` (`number`, optional) – request timeout in ms (default: `300000` - 5 minutes)
|
|
@@ -357,8 +357,9 @@ console.log(result.getObfuscatedCode());
|
|
|
357
357
|
|
|
358
358
|
**Returns:** `Promise<ObfuscationResult>`
|
|
359
359
|
|
|
360
|
+
> **Note:** When no Pro feature (`vmObfuscation` or `parseHtml`) is enabled, the Pro API is not needed, so `obfuscatePro` falls back to the basic (local) obfuscation API and no API request is made.
|
|
361
|
+
|
|
360
362
|
**Throws:** `ApiError` if:
|
|
361
|
-
- No Pro features (`vmObfuscation` or `parseHtml`) are enabled in options
|
|
362
363
|
- API token is invalid or expired
|
|
363
364
|
- API request fails
|
|
364
365
|
|
|
@@ -554,6 +555,7 @@ Following options are available for the JS Obfuscator:
|
|
|
554
555
|
|
|
555
556
|
```javascript
|
|
556
557
|
{
|
|
558
|
+
advertisement: true,
|
|
557
559
|
compact: true,
|
|
558
560
|
controlFlowFlattening: false,
|
|
559
561
|
controlFlowFlatteningThreshold: 0.75,
|
|
@@ -617,6 +619,7 @@ Following options are available for the JS Obfuscator:
|
|
|
617
619
|
|
|
618
620
|
-o, --output
|
|
619
621
|
|
|
622
|
+
--advertisement <boolean>
|
|
620
623
|
--compact <boolean>
|
|
621
624
|
--config <string>
|
|
622
625
|
--control-flow-flattening <boolean>
|
|
@@ -634,6 +637,7 @@ Following options are available for the JS Obfuscator:
|
|
|
634
637
|
--identifier-names-generator <string> [dictionary, hexadecimal, mangled, mangled-shuffled]
|
|
635
638
|
--identifiers-dictionary '<list>' (comma separated)
|
|
636
639
|
--identifiers-prefix <string>
|
|
640
|
+
--random-identifiers-prefix <boolean>
|
|
637
641
|
--ignore-imports <boolean>
|
|
638
642
|
--log <boolean>
|
|
639
643
|
--numbers-to-expressions <boolean>
|
|
@@ -667,6 +671,7 @@ Following options are available for the JS Obfuscator:
|
|
|
667
671
|
--string-array-wrappers-type <string> [variable, function]
|
|
668
672
|
--string-array-threshold <number>
|
|
669
673
|
--target <string> [browser, browser-no-eval, node]
|
|
674
|
+
--browser-environment <string> [http, https]
|
|
670
675
|
--transform-object-keys <boolean>
|
|
671
676
|
--unicode-escape-sequence <boolean>
|
|
672
677
|
--pro-api-token <string>
|
|
@@ -678,6 +683,7 @@ Following options are available for the JS Obfuscator:
|
|
|
678
683
|
--vm-target-functions '<list>' (comma separated)
|
|
679
684
|
--vm-exclude-functions '<list>' (comma separated)
|
|
680
685
|
--vm-target-functions-mode <string> [root, comment]
|
|
686
|
+
--vm-force-compile-dynamic-code <boolean>
|
|
681
687
|
--vm-wrap-top-level-initializers <boolean>
|
|
682
688
|
--vm-opcode-shuffle <boolean>
|
|
683
689
|
--vm-bytecode-encoding <boolean>
|
|
@@ -691,12 +697,19 @@ Following options are available for the JS Obfuscator:
|
|
|
691
697
|
--vm-split-dispatcher <boolean>
|
|
692
698
|
--vm-macro-ops <boolean>
|
|
693
699
|
--vm-debug-protection <boolean>
|
|
700
|
+
--vm-self-defending <boolean>
|
|
694
701
|
--vm-runtime-opcode-derivation <boolean>
|
|
695
702
|
--vm-stateful-opcodes <boolean>
|
|
703
|
+
--vm-async-executor <boolean>
|
|
704
|
+
--vm-call-context-opcodes <boolean>
|
|
696
705
|
--vm-stack-encoding <boolean>
|
|
697
706
|
--vm-randomize-keys <boolean>
|
|
698
707
|
--vm-indirect-dispatch <boolean>
|
|
699
708
|
--vm-compact-dispatcher <boolean>
|
|
709
|
+
--vm-register-based <boolean>
|
|
710
|
+
--vm-string-array-bytecode-only <boolean>
|
|
711
|
+
--vm-domain-lock '<list>' (comma separated)
|
|
712
|
+
--vm-domain-lock-redirect-url <string>
|
|
700
713
|
--vm-bytecode-format <string> [binary, json]
|
|
701
714
|
--parse-html <boolean>
|
|
702
715
|
--strict-mode <boolean>
|
|
@@ -704,6 +717,13 @@ Following options are available for the JS Obfuscator:
|
|
|
704
717
|
|
|
705
718
|
<!-- ##options-start## -->
|
|
706
719
|
|
|
720
|
+
### `advertisement`
|
|
721
|
+
Type: `boolean` Default: `true`
|
|
722
|
+
|
|
723
|
+
Allows to control the display of the JavaScript Obfuscator Pro advertisement message in the console.
|
|
724
|
+
|
|
725
|
+
The message is only shown when using the Node.js CLI in an interactive (TTY) terminal, is never shown in CI environments or in the browser, and is limited to a few displays. Set this option to `false` to disable the advertisement message completely.
|
|
726
|
+
|
|
707
727
|
### `compact`
|
|
708
728
|
Type: `boolean` Default: `true`
|
|
709
729
|
|
|
@@ -1968,6 +1988,35 @@ function outer() {
|
|
|
1968
1988
|
|
|
1969
1989
|
**When to use:** When you need surgical control over exactly which functions get VM protection, especially nested functions that contain sensitive logic. Unlike `vmTargetFunctions` which only works with root-level named functions, comment mode lets you protect any function anywhere in your code.
|
|
1970
1990
|
|
|
1991
|
+
### `vmForceCompileDynamicCode`
|
|
1992
|
+
Type: `boolean` Default: `false`
|
|
1993
|
+
|
|
1994
|
+
Controls what VM obfuscation does with a function that contains a direct `eval`, `new Function(...)`, or `Function(...)` call.
|
|
1995
|
+
|
|
1996
|
+
By default, such a function (and every function defined inside it) is skipped from VM bytecoding and a `VMDynamicCodeSkipped` warning is reported on `result.getWarnings()`. This is because the runtime-built source may reference identifiers from the surrounding scope chain — identifiers that the obfuscator has renamed.
|
|
1997
|
+
|
|
1998
|
+
When set to `true`, the function is bytecoded anyway and the `VMDynamicCodeSkipped` warning is no longer emitted.
|
|
1999
|
+
|
|
2000
|
+
The separate `DynamicCodeRenameRisk` warning continues to fire regardless of this option, because the rename risk it describes is independent of the VM skip — turning this option on does not make the underlying pattern any safer.
|
|
2001
|
+
|
|
2002
|
+
```javascript
|
|
2003
|
+
// Source code
|
|
2004
|
+
function loadConfig(src) {
|
|
2005
|
+
return eval(src);
|
|
2006
|
+
}
|
|
2007
|
+
loadConfig('1 + 2');
|
|
2008
|
+
```
|
|
2009
|
+
|
|
2010
|
+
```javascript
|
|
2011
|
+
// Options
|
|
2012
|
+
{
|
|
2013
|
+
vmObfuscation: true,
|
|
2014
|
+
vmForceCompileDynamicCode: true
|
|
2015
|
+
}
|
|
2016
|
+
```
|
|
2017
|
+
|
|
2018
|
+
With the option off (default), `loadConfig` is left as plain JavaScript. With the option on, `loadConfig` is compiled to VM bytecode like any other function. Use this when you have audited the call site and know the runtime-built code does not depend on closure-renamed identifiers.
|
|
2019
|
+
|
|
1971
2020
|
### `vmWrapTopLevelInitializers`
|
|
1972
2021
|
Type: `boolean` Default: `false`
|
|
1973
2022
|
|
|
@@ -2065,6 +2114,44 @@ JavaScriptObfuscator.obfuscate(code, {
|
|
|
2065
2114
|
window.__VM_KEY__ = 'mySecretKey123';
|
|
2066
2115
|
```
|
|
2067
2116
|
|
|
2117
|
+
### `vmAsyncExecutor`
|
|
2118
|
+
Type: `boolean` Default: `false`
|
|
2119
|
+
|
|
2120
|
+
Enables the asynchronous VM executor, which lets [`vmBytecodeArrayEncodingKeyGetter`](#vmbytecodearrayencodingkeygetter) return a `Promise` (an **asynchronous** key getter) — so the decryption key can be fetched at runtime (network request, IndexedDB, etc.) instead of having to be available synchronously when the code loads.
|
|
2121
|
+
|
|
2122
|
+
**Heavily recommended for fully async codebases.** In this mode only `async` functions are virtualized — a synchronous function can't be made async without turning its return value into a `Promise` and breaking its callers — so code that is `async` throughout gets the most coverage. It still works when the root is synchronous (e.g. a sync IIFE / UMD wrapper): the outermost `async` functions inside are protected, and the sync parts are left as-is.
|
|
2123
|
+
|
|
2124
|
+
**What gets transformed:** every **outermost** `async` function, wherever it appears (including nested inside sync wrappers). The outermost async in each chain is the protected unit — everything inside it, sync and async, is compiled in. Synchronous functions and plain generators are left unobfuscated.
|
|
2125
|
+
```js
|
|
2126
|
+
function foo() { // sync — left as-is
|
|
2127
|
+
function bar() {} // sync — left as-is
|
|
2128
|
+
|
|
2129
|
+
async function baz() { // transformed
|
|
2130
|
+
// any code here, including calls to other async or sync functions
|
|
2131
|
+
}
|
|
2132
|
+
|
|
2133
|
+
async function bark() { // transformed
|
|
2134
|
+
// any code here, including calls to other async or sync functions
|
|
2135
|
+
}
|
|
2136
|
+
}
|
|
2137
|
+
```
|
|
2138
|
+
|
|
2139
|
+
**Skips and warnings.** Async generators are also left unobfuscated when an asynchronous key getter is active (an async generator must return its iterator synchronously and can't wait for the key). In the default `vmTargetFunctionsMode: 'root'` skips are silent (selection is automatic); in `comment` [mode](#vmtargetfunctionsmode) a warning is emitted through `ObfuscationResult.getWarnings()` whenever a function you explicitly marked can't be virtualized — it turned out synchronous, or it's an async generator under an async key getter.
|
|
2140
|
+
|
|
2141
|
+
The asynchronous key getter additionally requires `vmBytecodeArrayEncoding` with a `vmBytecodeArrayEncodingKeyGetter`.
|
|
2142
|
+
|
|
2143
|
+
**Usage example:**
|
|
2144
|
+
```ts
|
|
2145
|
+
JavaScriptObfuscator.obfuscate(code, {
|
|
2146
|
+
vmObfuscation: true,
|
|
2147
|
+
vmAsyncExecutor: true,
|
|
2148
|
+
vmBytecodeArrayEncoding: true,
|
|
2149
|
+
vmBytecodeArrayEncodingKey: 'mySecretKey123',
|
|
2150
|
+
// the key getter may now return a Promise
|
|
2151
|
+
vmBytecodeArrayEncodingKeyGetter: 'fetch("/vm-key").then((res) => res.text())'
|
|
2152
|
+
});
|
|
2153
|
+
```
|
|
2154
|
+
|
|
2068
2155
|
### `vmJumpsEncoding`
|
|
2069
2156
|
Type: `boolean` Default: `false`
|
|
2070
2157
|
|
|
@@ -2099,11 +2186,137 @@ Adds multi-layered tamper detection, anti-hooking, and anti-reverse-engineering
|
|
|
2099
2186
|
|
|
2100
2187
|
Strongly recommended to use together with [`vmDebugProtection`](#vmDebugProtection), [`vmBytecodeArrayEncodingKey`](#vmbytecodeArrayEncodingKey), and [`vmBytecodeArrayEncodingKeyGetter`](#vmbytecodeArrayEncodingKeyGetter).
|
|
2101
2188
|
|
|
2189
|
+
### `vmDefenseHook`
|
|
2190
|
+
Type: `{ name: string, aliases?: object }` Default: `''`
|
|
2191
|
+
|
|
2192
|
+
`vmDefenseHook` takes an object with two keys: **`name`** (required) and **`aliases`** (optional).
|
|
2193
|
+
|
|
2194
|
+
`name` is a **global function your host page defines** that a VM defense (`vmDebugProtection` / `vmSelfDefending`) calls with a signal object when it detects a hostile signal — a debugger or inspector, a headless / automation browser, an AI-coding-agent process, a disallowed domain, and so on. Use it to report the event to your backend (e.g. `navigator.sendBeacon`). The hook is a **pure telemetry sink**: its return value is ignored, and a missing or throwing hook is a silent no-op that can never disable a defense. To change what a defense *does* on detection, use [`vmDefenseReaction`](#vmdefensereaction).
|
|
2195
|
+
|
|
2196
|
+
`aliases` optionally renames the fields of that signal object — covered under *Renaming the signal fields* below.
|
|
2197
|
+
|
|
2198
|
+
**The signal object.** The hook receives a single `signal`:
|
|
2199
|
+
|
|
2200
|
+
- `source` — the specific detector that fired (see the table).
|
|
2201
|
+
- `category` — the group it reports under: `automation` (non-human browsers), `debugger` (a debugger/inspector is active), `sandbox` (instrumented/fake host), `domain` (domain-lock violation), `tamper` (built-ins patched at runtime), or `integrity` (the VM's own code was altered).
|
|
2202
|
+
- `score` / `threshold` — how strongly the detector fired and the value it had to reach; the hook fires only once `score >= threshold`. Most checks are all-or-nothing (a single decisive signal); `headless` sums several browser-shape signals, so its `score` is typically higher than its `threshold`.
|
|
2203
|
+
|
|
2204
|
+
| `source` | detects | `category` |
|
|
2205
|
+
|---|----------------------------------------------------------------------------------|---|
|
|
2206
|
+
| `integrity` | the obfuscated VM code itself has been modified | `integrity` |
|
|
2207
|
+
| `node` | browser-targeted code running under Node.js | `debugger` |
|
|
2208
|
+
| `debugger` | an attached or active debugger or inspector session, or a debug environment | `debugger` |
|
|
2209
|
+
| `headless` | a headless browser is used to run the code | `automation` |
|
|
2210
|
+
| `agent` | an AI coding-agent running the code | `automation` |
|
|
2211
|
+
| `timing` | an execution pause suggesting a breakpoint or a stepping debugger | `debugger` |
|
|
2212
|
+
| `sandbox` | the code runs in a sandbox or a faked host environment | `sandbox` |
|
|
2213
|
+
| `domain` | the page origin is not in the [`vmDomainLock`](#vmdomainlock) allow-list | `domain` |
|
|
2214
|
+
| `nativeHook` | a native built-in function has been replaced or hooked | `tamper` |
|
|
2215
|
+
|
|
2216
|
+
**Registering the hook.** Define it as a plain global **before** the obfuscated bundle loads — the VM runtime and its defenses run before your (protected) program, so many detections fire during startup:
|
|
2217
|
+
|
|
2218
|
+
```js
|
|
2219
|
+
// in your page, before the obfuscated script:
|
|
2220
|
+
window.__vmDetection = function (signal) { navigator.sendBeacon('/vm-defense', JSON.stringify(signal)); };
|
|
2221
|
+
```
|
|
2222
|
+
```js
|
|
2223
|
+
// obfuscation option:
|
|
2224
|
+
vmDefenseHook: { name: '__vmDetection' }
|
|
2225
|
+
```
|
|
2226
|
+
|
|
2227
|
+
> A hook defined *inside* the obfuscated source is registered too late to catch startup-time detections, and if it gets VM-compiled it can't be reached until your program runs. It's kept safe either way (a missing hook no-ops, and a re-entrancy guard prevents any runaway), but for complete coverage register it up front. To still protect your reporting logic, keep the registered hook a one-line buffer (`(window.__vmDet = window.__vmDet || []).push(signal)`) and read/send that buffer from your obfuscated code.
|
|
2228
|
+
|
|
2229
|
+
**Renaming the signal fields (`aliases`).** The default `source`/`category` values are descriptive names, so anyone instrumenting the callback (or reading the output) can recognise the protection and which detector fired. `aliases` renames signal fields to opaque tokens of your choice, applied inside the VM *before* the signal is emitted, so those names never appear in the output or reach the callback. Your app knows its own mapping and forwards the tokens to your backend.
|
|
2230
|
+
|
|
2231
|
+
Aliases are per field, keeping key and value renames separate: each field takes a `key` (the property name the callback receives); the string name-fields `source` and `category` also take a `values` map, while `score`/`threshold` are numbers and take only a `key`. The names you can map (anything else is rejected at build time):
|
|
2232
|
+
|
|
2233
|
+
- **field keys** — `source`, `category`, `score`, `threshold`
|
|
2234
|
+
- **`source` values** — `headless`, `agent`, `node`, `debugger`, `timing`, `sandbox`, `domain`, `nativeHook`, `integrity`
|
|
2235
|
+
- **`category` values** — `automation`, `debugger`, `sandbox`, `domain`, `tamper`, `integrity`
|
|
2236
|
+
|
|
2237
|
+
```js
|
|
2238
|
+
vmDefenseHook: {
|
|
2239
|
+
name: '__vmDetection',
|
|
2240
|
+
aliases: {
|
|
2241
|
+
source: { key: 'a8Qm', values: { headless: 'xP4m9Q' } },
|
|
2242
|
+
category: { key: 'p3Tx', values: { automation: 'bQ7s1M' } },
|
|
2243
|
+
score: { key: 's1' },
|
|
2244
|
+
threshold: { key: 't1' }
|
|
2245
|
+
}
|
|
2246
|
+
// the callback now receives e.g. { a8Qm: 'xP4m9Q', p3Tx: 'bQ7s1M', s1: <score>, t1: <threshold> }
|
|
2247
|
+
}
|
|
2248
|
+
```
|
|
2249
|
+
|
|
2250
|
+
This is fingerprint avoidance, not secrecy — the mapping can still be inferred by repeated testing — so its only benefit is not exposing stable, self-explanatory names. Unset entries keep their default names.
|
|
2251
|
+
|
|
2252
|
+
> A bare string (`vmDefenseHook: '__vmDetection'`) is accepted as shorthand for `{ name: '__vmDetection' }` but is **deprecated** — prefer the object form.
|
|
2253
|
+
|
|
2254
|
+
### `vmDefenseReaction`
|
|
2255
|
+
Type: `object` Default: `{ automation: 'break', debugger: 'decoy', sandbox: 'decoy', domain: 'break', tamper: 'break', integrity: 'break' }`
|
|
2256
|
+
|
|
2257
|
+
Configures how each detection category reacts. It does **not** enable anything — the defenses themselves are turned on by [`vmSelfDefending`](#vmselfdefending), [`vmDebugProtection`](#vmdebugprotection), and [`vmDomainLock`](#vmdomainlock); this option only selects *how* an enabled defense reacts. The **category is the unit of control** — every detector in a category enacts that category's reaction.
|
|
2258
|
+
|
|
2259
|
+
Each **category** groups the detectors that watch for one kind of hostile condition. A category only reacts when the option that emits its detectors is enabled:
|
|
2260
|
+
|
|
2261
|
+
| Category | Enabled by | Reacts when |
|
|
2262
|
+
|---|---|---|
|
|
2263
|
+
| `automation` | `vmSelfDefending` or `vmDebugProtection` | The code is being driven by software instead of a person: a headless or automated browser, a scraping / testing framework, or an AI coding-agent stepping the page. |
|
|
2264
|
+
| `debugger` | `vmDebugProtection` or `vmSelfDefending` | Someone has a debugger or the browser's developer-tools inspector open and is stepping through the running code to understand it. |
|
|
2265
|
+
| `sandbox` | `vmDebugProtection` | The code is not running in a real browser at all — it has been lifted into an emulated or scripted JavaScript environment to be executed and studied offline. |
|
|
2266
|
+
| `domain` | `vmDomainLock` | The code is running on a site you did not authorize: a host not in your [`vmDomainLock`](#vmdomainlock) allow-list (for example, your bundle copied onto someone else's domain). |
|
|
2267
|
+
| `tamper` | `vmSelfDefending` | The JavaScript environment around the VM has been modified to watch or hijack it, such as native browser built-ins swapped out for instrumented versions. |
|
|
2268
|
+
| `integrity` | `vmSelfDefending` | The protected bundle's own code has been edited or patched since you generated it. |
|
|
2269
|
+
|
|
2270
|
+
Every category maps to one or more of [`vmSelfDefending`](#vmselfdefending), [`vmDebugProtection`](#vmdebugprotection), and [`vmDomainLock`](#vmdomainlock); there is no category outside those three options, and a reaction set for a category whose option is off simply has no effect.
|
|
2271
|
+
|
|
2272
|
+
Keys are these six category names, or `default` (a fallback for unspecified categories). Values are:
|
|
2273
|
+
|
|
2274
|
+
- `break` — break immediately
|
|
2275
|
+
- `decoy` — keep running on poisoned state, silently producing wrong results
|
|
2276
|
+
- `none` — do nothing locally (telemetry only)
|
|
2277
|
+
|
|
2278
|
+
The per-category defaults are shown above; a category you don't set (or set to its default value) uses that default. `default` reaches **every** category, including the correct-by-construction ones (`integrity`, `tamper`), so `{ default: 'none' }` is a genuinely non-breaking, telemetry-only build:
|
|
2279
|
+
|
|
2280
|
+
```js
|
|
2281
|
+
vmDefenseReaction: { default: 'none' } // never break — pair with vmDefenseHook
|
|
2282
|
+
vmDefenseReaction: { automation: 'none', domain: 'break' } // tolerate automation FPs, still break on a bad domain
|
|
2283
|
+
```
|
|
2284
|
+
|
|
2285
|
+
### `browserEnvironment`
|
|
2286
|
+
Type: `object` Default: `{}`
|
|
2287
|
+
|
|
2288
|
+
Declares facts about the environment your production build is served in, so the protected code can bind itself to them. Only takes effect together with [`vmSelfDefending`](#vmselfdefending), and only for `browser` / `browser-no-eval` / `service-worker` targets — it is rejected for `node`, `userscript`, and `bytenode`.
|
|
2289
|
+
|
|
2290
|
+
Currently one field:
|
|
2291
|
+
|
|
2292
|
+
- **`transport`** — the scheme your production serves the bundle over: `'http'` or `'https'`. With `'https'`, the build ties its integrity to being served over HTTPS, so a copy an analyst lifts and serves over plain HTTP (a common local reverse-engineering setup) will not run correctly. `'http'` or an unset field adds no binding.
|
|
2293
|
+
|
|
2294
|
+
```js
|
|
2295
|
+
browserEnvironment: { transport: 'https' }
|
|
2296
|
+
```
|
|
2297
|
+
|
|
2298
|
+
> :warning: A build declared `transport: 'https'` runs correctly **only** where it is actually served over `https:`. Every other scheme corrupts it, so declare it only when every context that loads your production build is HTTPS. That excludes: plain `http://` (including `http://localhost` in development), `file://` (Electron / Cordova / packaged apps), and `blob:` / `about:` embeddings (a bundle running inside an `about:blank` or `srcdoc` iframe). A client-side HTTP→HTTPS redirect still renders the HTTP page first, so the bundle must not run before the redirect completes.
|
|
2299
|
+
|
|
2102
2300
|
### `vmStatefulOpcodes`
|
|
2103
2301
|
Type: `boolean` Default: `false`
|
|
2104
2302
|
|
|
2105
2303
|
Makes opcode meanings depend on position in the bytecode. Each position has a different opcode-to-handler mapping derived from a seed, so the same opcode number performs different operations at different positions.
|
|
2106
2304
|
|
|
2305
|
+
### `vmCallContextOpcodes`
|
|
2306
|
+
Type: `boolean` Default: `false`
|
|
2307
|
+
|
|
2308
|
+
Makes a protected function depend on where it's called from, so it can't be lifted out of the code and run or analyzed on its own — it only behaves correctly when invoked through its real call sites in the program. This option affects runtime performance.
|
|
2309
|
+
|
|
2310
|
+
Currently only the following constructions are supported:
|
|
2311
|
+
|
|
2312
|
+
- function declarations (`function f() {}`);
|
|
2313
|
+
- function expressions and arrow functions assigned to a variable (`const f = () => {}`);
|
|
2314
|
+
- instance private methods (`this.#m()`).
|
|
2315
|
+
|
|
2316
|
+
In every case the function must always be reached through a direct call (`f()`, `this.#m()`). If it is stored in another variable, passed as an argument, or otherwise used as a value, it is left unprotected. Async functions are supported; generators are not.
|
|
2317
|
+
|
|
2318
|
+
This option is experimental and may break your code, so test the output thoroughly before using it.
|
|
2319
|
+
|
|
2107
2320
|
### `vmStackEncoding`
|
|
2108
2321
|
Type: `boolean` Default: `false`
|
|
2109
2322
|
|
|
@@ -2119,6 +2332,17 @@ Uses a single VM executor instead of dual executors (sync + generator). Reduces
|
|
|
2119
2332
|
- `false` (default): dual executors — optimal performance, larger output
|
|
2120
2333
|
- `true`: single executor — smaller output, slightly slower
|
|
2121
2334
|
|
|
2335
|
+
### `vmRegisterBased`
|
|
2336
|
+
Type: `boolean` Default: `false`
|
|
2337
|
+
|
|
2338
|
+
Switches the VM from the default stack-based bytecode to a register-based execution model, which improves VM runtime performance in some cases by ~15-20%, but slightly increases obfuscated code size.
|
|
2339
|
+
|
|
2340
|
+
Because it emits a structurally different bytecode and executor, it also gives the VM a more unique fingerprint than the default stack-based one — use it when you want to vary the VM's shape so it is less recognizable to generic analysis.
|
|
2341
|
+
|
|
2342
|
+
Under the hood this isn't a native register-based compiler — the regular stack-based compiler still generates the bytecode, which a separate transformation stage then rewrites into register-based form.
|
|
2343
|
+
|
|
2344
|
+
This option is experimental - test that your code runs well when `vmRegisterBased` is enabled.
|
|
2345
|
+
|
|
2122
2346
|
### `vmStringArrayBytecodeOnly`
|
|
2123
2347
|
Type: `boolean` Default: `false`
|
|
2124
2348
|
|
|
@@ -2131,6 +2355,25 @@ When enabled, the string array will **only** extract strings from bytecode data
|
|
|
2131
2355
|
- `stringArrayThreshold` still controls what percentage of those bytecode strings are extracted
|
|
2132
2356
|
|
|
2133
2357
|
|
|
2358
|
+
### `vmDomainLock`
|
|
2359
|
+
Type: `string[]` Default: `[]`
|
|
2360
|
+
|
|
2361
|
+
##### :warning: This option does not work with `target: 'node'`, `target: 'service-worker'` or `target: 'bytenode'`
|
|
2362
|
+
|
|
2363
|
+
Restricts the obfuscated code to specific domains and/or sub-domains, and is much harder to locate and strip than `domainLock`.
|
|
2364
|
+
|
|
2365
|
+
If the source code isn't run on the domains specified by this option, the browser will be redirected to the URL passed to [`vmDomainLockRedirectUrl`](#vmdomainlockredirecturl), and further protected calls will return incorrect results even if the redirect is suppressed.
|
|
2366
|
+
|
|
2367
|
+
##### Multiple domains and sub-domains
|
|
2368
|
+
It's possible to lock your code to more than one domain or sub-domain. For instance, to lock it so the code only runs on **www.example.com** add `www.example.com`. To make it work on the root domain including any sub-domains (`example.com`, `sub.example.com`), use `.example.com`.
|
|
2369
|
+
|
|
2370
|
+
### `vmDomainLockRedirectUrl`
|
|
2371
|
+
Type: `string` Default: `about:blank`
|
|
2372
|
+
|
|
2373
|
+
##### :warning: This option does not work with `target: 'node'`, `target: 'service-worker'` or `target: 'bytenode'`
|
|
2374
|
+
|
|
2375
|
+
Allows the browser to be redirected to a passed URL if the source code isn't run on the domains specified by [`vmDomainLock`](#vmdomainlock).
|
|
2376
|
+
|
|
2134
2377
|
### `strictMode`
|
|
2135
2378
|
Type: `boolean | null` Default: `null`
|
|
2136
2379
|
|
|
@@ -2197,6 +2440,15 @@ JavaScriptObfuscator.obfuscate(html, {
|
|
|
2197
2440
|
// output: HTML with only the marked script obfuscated
|
|
2198
2441
|
```
|
|
2199
2442
|
|
|
2443
|
+
### `randomIdentifiersPrefix`
|
|
2444
|
+
Type: `boolean` Default: `false`
|
|
2445
|
+
|
|
2446
|
+
Appends a seeded random prefix (6 alphanumeric characters) to all global identifiers. Use this option to avoid collisions between separately obfuscated bundles that are loaded into the same global scope — it removes the need to pick a unique `identifiersPrefix` per bundle manually.
|
|
2447
|
+
|
|
2448
|
+
- The random value is derived from the `seed` option and the source code hash, so reproducible builds with the same seed produce the same prefix.
|
|
2449
|
+
- When combined with `identifiersPrefix`, the random characters are appended to the user-provided prefix (e.g. `myApp` + random `aBc123` → `myAppaBc123`).
|
|
2450
|
+
- When combined with `vmObfuscation`, the random value replaces the default `vm` prefix — randomness already guarantees uniqueness.
|
|
2451
|
+
|
|
2200
2452
|
## Frequently Asked Questions
|
|
2201
2453
|
|
|
2202
2454
|
### What javascript versions are supported?
|