# jso-protector-reactnative

Mobile RASP (Runtime Application Self-Protection) for React Native /
Cordova / Ionic apps protected with **JavaScript Obfuscator**.

JSO's build-time obfuscation makes your shipped JS bundle unreadable.
This package adds the *runtime* half for mobile: a guard that runs inside
the app, detects root / jailbreak / Frida / emulator / signature
tampering, scores the result, routes it to your SIEM, and fires a
response you control.

It is the mobile counterpart to the browser `jso-protector/runtime/*`
modules (third-party-inventory, countermeasures, ai-script-governance)
and uses the same beacon envelope shape, so the `jso-beacon-slack` SIEM
adapters forward mobile threats with no adapter change.

## Two signal sources

| Source | Examples | Strength |
|---|---|---|
| **JS-observable** (this package, pure JS) | Frida globals, `Function.prototype.toString` tamper, suspicious globals, `__DEV__`-in-release, instrumentation timing anomaly | Weak / evadable — a tripwire, not a guarantee |
| **Native probe** (host-wired module) | root, jailbreak, Magisk, unc0ver, checkra1n, Dopamine, emulator, Frida/Xposed/Substrate hooks, app-signature mismatch | Strong / authoritative — pure JS cannot read the FS or process maps |

> **Honest threat model.** JS-only detection raises the cost of casual
> tampering and catches unsophisticated attaches, but a determined
> attacker with a native hook can hide most JS-observable signals. The
> assurance lives in the native probe. Ship both.

## Install

```
npm install https://javascriptobfuscator.com/download/jso-protector-reactnative/jso-protector-reactnative-0.2.0.tgz
```

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

`jso-protector` and `react-native` are optional peer dependencies — the
pure RASP engine has zero runtime dependencies and runs anywhere
(including Node, for testing).

## Build-time (obfuscate the bundle)

Already handled by `jso-protector`'s Metro integration. This package
re-exports it for a single entry point:

```js
// metro.config.js
const { withMetro } = require("jso-protector-reactnative");
module.exports = withMetro(baseConfig, { apiKey: process.env.JSO_API_KEY, preset: "balanced" });
```

## Runtime (detect tampering)

```js
import { NativeModules } from "react-native";
import { createMobileGuard } from "jso-protector-reactnative";

const guard = createMobileGuard({
  nativeProbe: () => NativeModules.JsoRasp.probe(),   // see templates/
  beaconUrl:   "https://beacon.example.com/v1/jso/mobile",
  intervalMs:  30000,
  isReleaseBuild: !__DEV__,
  isDev: __DEV__,
  onThreat(report) {
    if (report.verdict === "compromised") { /* gate sensitive flows */ }
  },
});
guard.start();
```

See `examples/App.guard.js` for a complete wiring.

## Native modules

Pure JS can't read the device. The strong signals come from the bundled
self-contained native modules:

- `templates/android/JsoRaspModule.kt`
- `templates/android/JsoRaspPackage.kt`
- `templates/ios/JsoRasp.swift`

The Android probe checks root/Magisk artifacts, `su`, Frida ports and
process maps, Xposed, debugger/emulator state, installer source, and an
optional SHA-256 signing-certificate pin. The iOS probe checks jailbreak
artifacts and sandbox escape, loaded Frida/Substrate images, tracing,
simulator state, enterprise provisioning, and an optional Team ID pin.
Both return a result matching the `nativeProbeSchema` contract:

```
{ platform, isRooted, isJailbroken, isDebuggable, isEmulator,
  hooksDetected, signatureTampered, unofficialStore, detectedTools[] }
```

## Report shape

```json
{
  "v": 1,
  "kind": "mobile-rasp",
  "verdict": "compromised",
  "score": 110,
  "thresholds": { "suspicious": 30, "compromised": 60 },
  "signals": [
    { "id": "native.rooted", "source": "native", "weight": 60, "detail": "device is rooted" },
    { "id": "native.named-tool", "source": "native", "weight": 50, "detail": "detected tool: Magisk", "tool": "Magisk" }
  ],
  "platform": "android",
  "nativeProbePresent": true
}
```

`verdict` crosses to `suspicious` at score 30 and `compromised` at 60.
Weights are documented in `SIGNAL_WEIGHTS` and tunable per build.

For compromised devices, `respondOnCompromised` accepts `callback`,
`lock`, or `lock-and-callback`. Lock mode sets `globalThis.__jsoMobileLocked`
so navigation/auth/payment gates can fail closed; `onCompromised(report)`
provides the corresponding application hook.

## Testing

```
npm test
```

25 Node tests cover the pure-data engine (every signal, the scoring
thresholds, malformed input) and the guard orchestration (async probe,
probe-throw capture, beacon POST, threat-hook isolation, timer
lifecycle). No device required.
