Metadata-Version: 2.4
Name: shifra-api
Version: 2.2.0
Summary: SHIFRA server-driven licensing client for Python products
Author: Shifra
License: Proprietary
Project-URL: Documentation, https://github.com/o3rr/licensecloud-backend/blob/main/docs/loader-v2.md
Keywords: licensing,license-key,shifra,protection
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: MacOS
Classifier: Typing :: Typed
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Requires-Dist: cryptography>=41

# shifra-api

Server-driven licensing for Python products. You configure **one** thing: your
license key.

```python
from shifra_api import run

run("YOUR-LICENSE-KEY")
```

Everything else — which script runs, its version, heartbeat settings, device
and network policy, branding — is decided by the Shifra server from your key.

## Install

```bash
pip install shifra-api
```

Requires Python 3.9+ and the `cryptography` package (installed automatically).

> Distribution builds are produced by Shifra's build process, which embeds the
> API origin and the pinned signing key. A plain source checkout has neither and
> will refuse to start — that is intentional.

## Usage

### Run the protected script

```python
from shifra_api import run

run("YOUR-LICENSE-KEY")
```

That single call verifies the license and device, resolves the linked Python
product, downloads and verifies its published release, prints the Console
Identity configured by the workspace owner, runs the release under heartbeat
supervision, applies server-authorized updates, and closes the session on exit.

### Check a license without running anything

```python
from shifra_api import Shafra, ShafraError

try:
    license = Shafra("YOUR-LICENSE-KEY").verify()
except ShafraError as error:
    print(error.code, error.message)
else:
    print(license.product_name, license.product_version)
    print("expires:", license.expires_at)
```

### Hold a verified session while your own code runs

```python
from shifra_api import Shafra

with Shafra("YOUR-LICENSE-KEY") as session:
    app.run()          # heartbeat is active for the whole block
```

The session ends when the block exits. If the license is revoked mid-run, the
heartbeat stops and a `SessionRevoked` error is raised when the block closes.

## Errors

Every failure has a stable `code`. Import the specific class or catch
`ShafraError`:

| Code | Meaning |
|---|---|
| `LICENSE_INVALID` | Key not found |
| `LICENSE_EXPIRED` | License expired |
| `LICENSE_REVOKED` | License banned or revoked |
| `LICENSE_NOT_LINKED` | Key not assigned to a product yet |
| `HWID_MISMATCH` | Bound to a different device |
| `DEVICE_LIMIT_REACHED` | Too many devices for this license |
| `IP_NOT_ALLOWED` | Network not permitted |
| `LOADER_UPDATE_REQUIRED` | Update the client |
| `MAINTENANCE` | Service in maintenance |
| `NETWORK_TIMEOUT` / `NETWORK_ERROR` | Could not reach the server |
| `INVALID_SERVER_SIGNATURE` | Response failed verification |
| `PAYLOAD_INTEGRITY_FAILED` | Downloaded script failed its digest check |
| `SESSION_REVOKED` / `SESSION_EXPIRED` | Runtime session ended |

Connection problems are never reported as signature failures.

## About the hardware identity

The client derives a fingerprint from stable machine identifiers and sends only
a SHA-256 digest. Raw identifiers never leave your machine. This is a signal for
the server to bind licenses to devices, not hardware attestation.

## Security notes

- Responses are verified with an Ed25519 key embedded in the build. A signature
  received over the network is never used as a trust anchor.
- Downloads are checked against a signed digest before anything runs.
- The protected script runs in a supervised subprocess without a temporary
  plaintext source file, so heartbeat revocation can stop it. Anyone with
  control of the machine can still inspect process memory — this package
  protects authorization and integrity, not absolute source secrecy.
