# jso-protector-electron

Electron V8 bytecode adapter for `jso-protector`. Pair JSO obfuscation
with Electron's bytecode runtime to ship `.jsc` artefacts that combine
JSO protection with version-bound V8 cached data. Public bytecode tools
and an attached debugger still matter; this is a cost-raising layer, not
an unrecoverability guarantee.

## Pipeline

```
src/main.js
   |   jso-protector (HTTP API: obfuscate + sign + watermark)
   v
dist-protected/main.js
   |   jso-protector-electron (V8 cachedData -> .jsc)
   v
dist-bytecode/main.js.jsc        <-- ship this in your .asar
```

## Install

```sh
npm install --save-dev jso-protector \
  https://javascriptobfuscator.com/download/jso-protector-electron/jso-protector-electron-0.1.0.tgz
```

The adapter is a versioned direct download and is not published in the
npm registry. Pin the URL (or your mirrored copy) in the lockfile.

`electron` is a *peer* dependency. You need Electron in your build
environment for `mode: embedded` (the only mode that emits real
bytecode).

## Embedded mode (real bytecode)

Run under Electron's Node:

```sh
electron $(npm bin)/jso-protector-electron \
  --input  dist-protected \
  --output dist-bytecode \
  --mode   embedded
```

This walks `dist-protected/`, runs `vm.Script(src).createCachedData()`
for each `.js` file, and emits `dist-bytecode/<rel>.jsc` containing a
small JSON header followed by the V8 cachedData blob. The header
records the source bytes, jsc bytes, and Electron version so an
auditor can validate coverage:

```
[ 8 bytes magic "JSOJSC\x01\x00" ]
[ 4 bytes LE uint32 header length  ]
[ N bytes JSON: { filename, electronVersion, srcBytes, jscBytes }  ]
[ remaining bytes: V8 cachedData                                   ]
```

The output directory also contains `bytecode.manifest.json` listing
every processed + skipped file. Hand it to `jso-protector compliance
pci-dss-v4` as additional evidence.

## Scaffold-only mode (preview without Electron)

```sh
jso-protector-electron \
  --input  dist-protected \
  --output dist-bytecode \
  --mode   scaffold-only
```

Useful in CI environments where you can't run Electron (e.g. a
lint stage that just wants to confirm coverage). Output is the
original `.js` files plus per-file `<file>.bytecode-meta.json`
recording `{ sourceSha256, sourceBytes, generatedAt }`. The
top-level `bytecode.manifest.json` carries `mode: "scaffold-only"`
so a downstream verifier can refuse to ship until the real bytecode
build has run.

## Loader on the Electron side

In your Electron main process (or preload):

```js
const fs = require("node:fs");
const vm = require("node:vm");

function loadJsc(jscPath) {
    const buf = fs.readFileSync(jscPath);
    // Skip the 8-byte magic + 4-byte length + JSON header.
    const headerLen = buf.readUInt32LE(8);
    const cachedData = buf.subarray(12 + headerLen);
    const filename = JSON.parse(buf.subarray(12, 12 + headerLen).toString("utf8")).filename;
    const script = new vm.Script("", { filename: filename, cachedData: cachedData });
    return script.runInThisContext();
}
```

Wrap that in `app.whenReady().then(...)` and you've replaced your
ordinary `require` for protected modules.

## Threat model

| Layer | Defends against |
|---|---|
| JSO obfuscation | Casual reverse-engineering of the JS bundle |
| V8 bytecode | Skilled JS reverse-engineering; LLM-assisted decompilation |
| Ed25519 signed manifest | Post-build tampering (CDN swaps, supply-chain attacks) |
| Watermark | Anti-piracy / leak attribution |
| Beacon + SIEM | Detection / personnel alerts when any of the above fires |

None of these defeat a debugger attached to the running Electron
process. For that you need OS-level mitigations: code-signing,
notarization (macOS), hardened runtime, and Windows AppContainer.

## API (programmatic)

```js
const electron = require("jso-protector-electron");

const result = await electron.compileDirectory({
    input:      "dist-protected",
    output:     "dist-bytecode",
    mode:       "auto",             // "auto" | "embedded" | "scaffold-only"
    extensions: [".js", ".cjs", ".mjs"],
});
// result: { mode, processed, skipped, manifestPath }
```

The `auto` mode picks `embedded` when running under Electron and
`scaffold-only` otherwise. Always pass an explicit `mode` in CI so
the build fails loudly if Electron is missing.

## Verify

```sh
npm test
```

14 tests covering both modes, the CLI surface, the .jsc header layout,
the directory walk, and the actionable-error path when embedded mode
is invoked without Electron.
