Metadata-Version: 2.4
Name: keythai
Version: 0.1.0
Summary: Official KeyThai SDK — license activation, validation, Management API and offline Ed25519 verification for keythai.net
Project-URL: Homepage, https://keythai.net
Project-URL: Documentation, https://keythai.net/docs
Project-URL: Repository, https://github.com/pondlnwtrue007/keythai.git
Author: KeyThai
License-Expression: MIT
Keywords: drm,ed25519,keythai,license,license-key,licensing
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
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 :: Software Development :: Libraries
Requires-Python: >=3.9
Requires-Dist: cryptography>=41.0
Requires-Dist: requests>=2.28
Description-Content-Type: text/markdown

# keythai (Python)

Official [KeyThai](https://keythai.net) SDK for Python — license activation,
validation, the Management API, and **offline Ed25519 signature verification**.
Requires Python 3.9+.

```bash
pip install keythai
```

## Quickstart

```python
from keythai import KeyThaiClient, KeyThaiApiError, get_device_fingerprint

client = KeyThaiClient("kt_live_xxxxxxxxxxxx")
key = "KEYT-AB12-3C4D-5E6F-7G8H-9J0K"
fingerprint = get_device_fingerprint()

try:
    # Activate this machine (consumes one seat; idempotent per fingerprint)
    res = client.activate(key, fingerprint, name="My PC", platform_name="windows")
    print(res["valid"], res["status"], res["expires_at"])

    # Later: just check status
    v = client.validate(key, fingerprint)
    if not v["valid"]:
        print("not valid:", v["status"])
except KeyThaiApiError as e:
    print(f"[{e.code}] ({e.status}) {e.message}")
```

## Offline verification (Ed25519)

```python
from keythai import verify_signature, verify_lic_file

# Fetch the public JWK once and cache/embed it.
jwk = client.list_keys()["keys"][0]["publicJwk"]

# 1) Verify a live response
res = client.validate(key, fingerprint)
if not verify_signature(jwk, res):
    raise RuntimeError("signature mismatch — response was tampered")

# 2) Verify an offline .lic file (checks signature AND expires_at)
lic = verify_lic_file(jwk, lic_file_contents)
if not lic["valid"]:
    raise RuntimeError(lic["reason"])   # e.g. "license หมดอายุ"
print(lic["payload"]["expires_at"])
```

## Management API

```python
products = client.list_products()
policies = client.list_policies(products[0]["id"])

# Issue a license — the plaintext key is returned ONCE.
created = client.create_license(
    product=products[0]["code"],
    policy_id=policies[0]["id"],
    holder_name="สมชาย",
    holder_email="somchai@example.com",
    quantity=1,
)
print(created["licenses"][0]["key"])

page = client.list_licenses(status="active", q="somchai", page=1, limit=25)
client.update_license(created["licenses"][0]["key"], action="suspend")
client.remove_machine(created["licenses"][0]["key"], fingerprint)
```

## Error handling

Every non-2xx response raises `KeyThaiApiError` with `.code` (e.g.
`SEAT_LIMIT_REACHED`), `.status` (HTTP code) and `.message`. Codes:
`INVALID_KEY`, `LICENSE_SUSPENDED`, `LICENSE_REVOKED`, `LICENSE_EXPIRED`,
`SEAT_LIMIT_REACHED`, `MACHINE_NOT_FOUND`, `RATE_LIMITED`, `QUOTA_EXCEEDED`,
`UNAUTHORIZED`, `VALIDATION_ERROR`.

---

# คู่มือภาษาไทย

`keythai` คือ SDK อย่างเป็นทางการของ [KeyThai](https://keythai.net) สำหรับ Python 3.9+
— รองรับ activate / validate license, Management API และตรวจลายเซ็น Ed25519 แบบ offline

## ติดตั้ง

```bash
pip install keythai
```

## เริ่มต้นใช้งาน

```python
from keythai import KeyThaiClient, KeyThaiApiError, get_device_fingerprint

client = KeyThaiClient("kt_live_xxxxxxxxxxxx")
fp = get_device_fingerprint()

try:
    res = client.activate("KEYT-AB12-3C4D-5E6F-7G8H-9J0K", fp, platform_name="windows")
    print("สถานะ:", res["status"], "valid:", res["valid"])
except KeyThaiApiError as e:
    print(f"ผิดพลาด [{e.code}]: {e.message}")
```

## ตรวจลายเซ็น offline + ไฟล์ .lic

```python
from keythai import verify_lic_file

jwk = client.list_keys()["keys"][0]["publicJwk"]
lic = verify_lic_file(jwk, lic_file_contents)
if not lic["valid"]:
    raise RuntimeError(lic["reason"])  # เช่น "license หมดอายุ"
```

## ออก license อัตโนมัติ (Management API)

```python
created = client.create_license(
    product="my-app",
    policy_id="01J...",
    holder_name="สมชาย",
    quantity=1,
)
# created["licenses"][0]["key"] คือ plaintext key — แสดงครั้งเดียวเท่านั้น
```

## License

MIT © KeyThai
