Metadata-Version: 2.4
Name: intigin
Version: 1.0.0
Summary: Intigin dynamic-backend adapter — thin in-app WSGI middleware for view-source protection.
Author: Intigin
Project-URL: Homepage, https://intigin.com
Project-URL: Documentation, https://intigin.com/docs
Keywords: intigin,wsgi,middleware,view-source,protection,flask,django
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: Other/Proprietary License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Middleware
Classifier: Topic :: Security
Requires-Python: >=3.7
Description-Content-Type: text/markdown

# intigin

Thin in-app **WSGI adapter** for [Intigin](https://intigin.com) dynamic-backend protection. It wraps
your app so the same Intigin bundle that protects static sites also protects your server-rendered pages —
view-source shows only a loader shell, and the real HTML is reconstructed client-side.

The adapter does almost nothing: the browser bundle does the heavy lifting. On a page navigation it
returns a **clean loader shell** (no payload, no cookie); when the bundle asks for the page (a same-URL
fetch carrying an `X-Intigin-Payload` header) it encodes the finished HTML into the frozen wire format
and returns it. The bundle at `https://{host}/{token}.js` decodes and reconstructs the page, then
reveals, polls, and hot-swaps live like a static Intigin page — no backend round-trip on updates.

## Install

```bash
pip install intigin
```

## Use

Wrap your WSGI callable with a scoped Gateway API key (dashboard → **Settings → Gateway API**). The
adapter resolves your public bundle token from the key once at boot, so no token is hardcoded:

```python
from intigin import Intigin

app.wsgi_app = Intigin(app.wsgi_app, api_key="iga_...", host="intigin.com")   # recommended
```

Flask uses `app.wsgi_app`; Django wraps `application` in `wsgi.py`. A raw 32-hex `token="..."` is also
accepted for a zero-config demo.

## Behavior

- **Cookieless.** The payload rides the bundle's marker fetch (the browser's own session), so nothing
  payload-related appears in the source and no cookie is set — cookie blockers don't affect it.
- **Non-HTML passes through** untouched; only top-level HTML navigations are wrapped.
- **Fail-closed.** A bad/missing key or any wrap error disables the adapter (serves your app
  unprotected, logged to stderr) or returns a self-contained restricted page — never the raw HTML for a
  failed encode.
- **Kill-switch.** `INTIGIN_ADAPTER_MODE=wrap|passthrough|off` (env). `passthrough`/`off` removes the
  adapter from the path.

## Conformance

```bash
python -m intigin --selftest
```

Verifies the frozen wire format — `base64("IGP1" + FLAGS + BODY)`, `BODY = xor(deflate(utf8(html)),
sha256(token))` — against the browser bundle's decoder.

> **Concealment, not encryption.** The scramble key is derived from the public bundle token, so this
> defeats view-source and naive scrapers, not cryptanalysis. Object-level authorization stays in your
> own routes.
