Metadata-Version: 2.5
Name: jso-protector
Version: 0.1.0
Summary: Python client for the JavaScript Obfuscator HTTP API. Companion to the jso-protector npm CLI.
Project-URL: Homepage, https://javascriptobfuscator.com/
Project-URL: Repository, https://github.com/javascriptobfuscator-com/jso-protector-python
Project-URL: Documentation, https://javascriptobfuscator.com/docs/
Project-URL: npm CLI, https://javascriptobfuscator.com/docs/npmcli.aspx
Author: JavaScript Obfuscator
License: JavaScript Obfuscator — jso-protector (Python client)
        Proprietary Software Licence
        
        Copyright (c) 2026 JavaScript Obfuscator. All rights reserved.
        
        This software is licensed, not sold. It is made publicly installable through a
        public package registry as a convenience for licensees and evaluators.
        Publication on a public registry does not place it in the public domain and does
        not grant any open-source licence.
        
        This package is a client library for the JavaScript Obfuscator hosted API. It
        contains no protection engine and no runtime components; it sends source code to
        the hosted service and returns the result.
        
        1. GRANT
        
           Subject to the terms below, you are granted a non-exclusive, non-transferable,
           revocable licence to:
        
           (a) download, install and execute this package;
        
           (b) use it to protect source code that you own or are authorised to modify;
               and
        
           (c) vendor an unmodified copy of this package into your own build or
               deployment artifacts, where your toolchain requires dependencies to be
               committed or bundled, provided this licence notice travels with it.
        
        2. RESTRICTIONS
        
           Except as expressly permitted in Section 1, and except where the following
           cannot lawfully be restricted in your jurisdiction, you may not:
        
           (a) redistribute, sublicense, sell, rent, lease or host this package or any
               part of it as a standalone offering;
        
           (b) modify, adapt or create derivative works of this package;
        
           (c) reverse engineer, decompile or disassemble it, other than to the extent
               required for interoperability where that right is granted by applicable
               law;
        
           (d) remove, obscure or alter any copyright, licence or attribution notice; or
        
           (e) use it to protect code that you neither own nor are authorised to modify.
        
        3. THE HOSTED SERVICE
        
           This client transmits source code to the JavaScript Obfuscator hosted API.
           Substantially all of its functionality requires a valid, current subscription
           or a free-tier account, and your use of the service is additionally governed
           by the terms published at https://javascriptobfuscator.com/. Nothing in this
           licence grants access to the hosted service, and nothing in it limits or
           varies those service terms.
        
        4. NO WARRANTY
        
           THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
           IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
           FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
        
           No representation is made that obfuscated or protected output cannot be
           analysed, reverse engineered or recovered. Code protection raises the cost of
           analysis; it does not make it impossible. Do not rely on this software as the
           sole control protecting secrets, credentials or safety-critical logic.
        
        5. LIMITATION OF LIABILITY
        
           IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR
           OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
           FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF OR OTHER
           DEALINGS IN THE SOFTWARE.
        
        6. TERMINATION
        
           This licence terminates automatically if you breach any of its terms. On
           termination you must cease all use and destroy all copies.
        
        7. GOVERNING LAW
        
           This licence is governed by the laws of the jurisdiction in which the
           copyright holder is established, without regard to conflict-of-law rules.
        
        Questions about licensing: https://javascriptobfuscator.com/
License-File: LICENSE
Keywords: anti-tamper,javascript,javascript-obfuscator,obfuscation,protection,symbolication
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.8
Description-Content-Type: text/markdown

# jso-protector — Python client

Python client for the [JavaScript Obfuscator](https://javascriptobfuscator.com/) HTTP API. Mirrors the protect() surface of the [npm `jso-protector` CLI](https://javascriptobfuscator.com/docs/npmcli.aspx) so behavior stays in lockstep across runtimes.

Pure stdlib — uses `urllib` and `json`. No third-party dependency.

## Install

```bash
pip install jso-protector
```

## Quick start

```python
from jso_protector import protect

result = protect(
    # Credentials default to JSO_API_KEY / JSO_API_PASSWORD env vars.
    files={"app.js": open("dist/app.js").read()},
    preset="balanced",
    label="ci-build-7f3a",   # tags the request with this release label
)

for name, code in result.files.items():
    with open(f"dist-protected/{name}", "w") as fh:
        fh.write(code)

print("BuildId:", result.build_id)
print("Fingerprint:", result.polymorphism_fingerprint)
```

## Credentials

The client reads `JSO_API_KEY` / `JSO_API_PASSWORD` (or the long-form `JAVASCRIPT_OBFUSCATOR_API_KEY` / `JAVASCRIPT_OBFUSCATOR_API_PASSWORD`) from the environment before falling back to the `api_key=` / `api_password=` keyword arguments. Use env vars on shared / CI machines so the keys never appear in source.

## Presets

| Preset | Notes |
|---|---|
| `standard` | Core string encoding, string-array move, name mangling, compression. |
| `balanced` | Adds string encryption, deep obfuscation, flat transform, code transposition. |
| `maximum` | Adds member rename, global rename, member move, dead-code insertion. |

For fine-grained control pass `options={...}` with the same Pascal-case keys the [HTTP API](https://javascriptobfuscator.com/docs/) documents — e.g. `options={"LockDate": True, "LockDomain": True, "LockDomainList": "example.com"}`. Explicit options override preset defaults.

## Returned data

`ProtectResult` is a dataclass with five fields:

| Field | Type | Notes |
|---|---|---|
| `files` | `dict[str, str]` | Protected source keyed by input filename. |
| `build_id` | `str \| None` | Stable identifier for this protection run. Inject as a global so production crash reports carry the matching BuildId. |
| `polymorphism_fingerprint` | `str \| None` | Short fingerprint over the protected output. Auditors use this to prove builds genuinely diverge. |
| `report` | `dict` | Full Report object — identifier maps, enabled options, compatibility findings, release metadata. |
| `raw` | `dict` | The complete raw response body. Use when a field hasn't been surfaced on the dataclass yet. |

## Error handling

```python
from jso_protector import protect, ProtectError

try:
    result = protect(files={"app.js": code})
except ProtectError as e:
    # e.message is safe to log — API key / password are never interpolated.
    # e.type and e.error_code carry the API's Type / ErrorCode when present.
    print(f"JSO protection failed: {e}")
```

## Watermarking — anti-piracy / dispute proof

The `jso_protector.watermark` module embeds an HMAC-SHA256-signed marker into source before it goes to the obfuscation API. The obfuscator's `KeepComment` option preserves the marker through every transform, so the watermark survives in the protected output. Holders of the secret can verify; everyone else sees an opaque comment block.

```python
from jso_protector import protect, watermark

# Stamp during build:
source = open("dist/app.js").read()
stamped = watermark.inject_into(source, tag="release-2026-Q3", key=os.environ["JSO_WATERMARK_KEY"])
result = protect(files={"app.js": stamped}, preset="balanced",
                 options={"KeepComment": True})    # required so the marker survives

# Verify a protected artifact later:
r = watermark.verify(open("dist-protected/app.js").read(), key=os.environ["JSO_WATERMARK_KEY"])
if r.valid:
    print(f"Valid build, tag={r.tag}")
elif r.present:
    print(f"Watermark present (tag={r.tag}) but signature does NOT match the supplied key.")
else:
    print("No watermark in this file.")
```

Wire format is identical to the Node (`packages/jso-protector/watermark.js`) and .NET (`JsoProtector.Watermark`) clients — an artifact stamped by any of the three verifies under any of the others. Tests in `tests/test_watermark.py` include cross-language verification with the Node implementation (skipped when `node` isn't on PATH). Spec: <https://javascriptobfuscator.com/docs/wireformat.aspx#watermark>.

Lookup-only mode (no key supplied) extracts the embedded tag without validating — useful for forensic inspection of leaked artifacts where the secret shouldn't ship to the investigator. Constant-time HMAC compare via `hmac.compare_digest`.

## Stack-trace symbolication

Persist `result.report` (or just `result.report["GlobalIdentifierMap"]` and `result.report["MemberIdentifierMap"]`) alongside the protected dist. When a production crash arrives, demangle locally with the [`jso-symbolicate` npm package](https://javascriptobfuscator.com/docs/symbolication.aspx) — or, for a Python-only pipeline, the identifier map is plain JSON that you can iterate over and substitute against the stack text yourself.

## License

UNLICENSED. Provided as a free companion to the JSO service. An active JSO account is required to make API calls.
