htl-verify 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- htl_verify-1.0.0/PKG-INFO +49 -0
- htl_verify-1.0.0/README.md +32 -0
- htl_verify-1.0.0/htl_verify/__init__.py +67 -0
- htl_verify-1.0.0/htl_verify.egg-info/PKG-INFO +49 -0
- htl_verify-1.0.0/htl_verify.egg-info/SOURCES.txt +7 -0
- htl_verify-1.0.0/htl_verify.egg-info/dependency_links.txt +1 -0
- htl_verify-1.0.0/htl_verify.egg-info/top_level.txt +1 -0
- htl_verify-1.0.0/pyproject.toml +24 -0
- htl_verify-1.0.0/setup.cfg +4 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: htl-verify
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Verify X-Trust signed human-presence headers. Standard library only.
|
|
5
|
+
Author-email: Dieng <diengamine.htl@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/htl-syterme/htl-core
|
|
8
|
+
Project-URL: Repository, https://github.com/htl-syterme/htl-core
|
|
9
|
+
Project-URL: Spec, https://github.com/htl-syterme/htl-core/blob/main/SPEC.md
|
|
10
|
+
Keywords: trust,human-proof,anti-bot,x-trust,llm,ai-infrastructure
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
|
|
14
|
+
Classifier: Topic :: Security
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# htl-verify
|
|
19
|
+
|
|
20
|
+
Verify X-Trust signed human-presence headers in Python. Standard library only.
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
pip install htl-verify
|
|
25
|
+
|
|
26
|
+
## Use
|
|
27
|
+
|
|
28
|
+
from htl_verify import verify, Untrusted
|
|
29
|
+
|
|
30
|
+
try:
|
|
31
|
+
claims = verify(header, key=secret_bytes)
|
|
32
|
+
score = claims["score"]
|
|
33
|
+
if score >= 0.5:
|
|
34
|
+
pass # annotated as likely-human
|
|
35
|
+
except Untrusted:
|
|
36
|
+
pass # treat as unverified; never blocks by default
|
|
37
|
+
|
|
38
|
+
## What it is not
|
|
39
|
+
|
|
40
|
+
Not a CAPTCHA, not identity, not bot authentication. The score is a signal,
|
|
41
|
+
not a proof. A determined client can raise its own score; that is a property
|
|
42
|
+
of any client-side signal and is documented in the project SPEC.
|
|
43
|
+
|
|
44
|
+
## Wire format
|
|
45
|
+
|
|
46
|
+
X-Trust: v1.<payload_b64url>.<sig_b64url>
|
|
47
|
+
|
|
48
|
+
Payload JSON: `{sub, score, iat, exp, nonce?}`. HMAC-SHA256 over the
|
|
49
|
+
base64url payload. TTL 120s. Score 0..1.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# htl-verify
|
|
2
|
+
|
|
3
|
+
Verify X-Trust signed human-presence headers in Python. Standard library only.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
pip install htl-verify
|
|
8
|
+
|
|
9
|
+
## Use
|
|
10
|
+
|
|
11
|
+
from htl_verify import verify, Untrusted
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
claims = verify(header, key=secret_bytes)
|
|
15
|
+
score = claims["score"]
|
|
16
|
+
if score >= 0.5:
|
|
17
|
+
pass # annotated as likely-human
|
|
18
|
+
except Untrusted:
|
|
19
|
+
pass # treat as unverified; never blocks by default
|
|
20
|
+
|
|
21
|
+
## What it is not
|
|
22
|
+
|
|
23
|
+
Not a CAPTCHA, not identity, not bot authentication. The score is a signal,
|
|
24
|
+
not a proof. A determined client can raise its own score; that is a property
|
|
25
|
+
of any client-side signal and is documented in the project SPEC.
|
|
26
|
+
|
|
27
|
+
## Wire format
|
|
28
|
+
|
|
29
|
+
X-Trust: v1.<payload_b64url>.<sig_b64url>
|
|
30
|
+
|
|
31
|
+
Payload JSON: `{sub, score, iat, exp, nonce?}`. HMAC-SHA256 over the
|
|
32
|
+
base64url payload. TTL 120s. Score 0..1.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""htl-verify - X-Trust header verifier. Standard library only, zero dependencies."""
|
|
2
|
+
import base64
|
|
3
|
+
import hashlib
|
|
4
|
+
import hmac
|
|
5
|
+
import json
|
|
6
|
+
import time
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
__version__ = "1.0.0"
|
|
10
|
+
__all__ = ["verify", "Untrusted"]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Untrusted(Exception):
|
|
14
|
+
"""Raised when an X-Trust header fails verification."""
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _b64d(s: str) -> bytes:
|
|
18
|
+
pad = "=" * (-len(s) % 4)
|
|
19
|
+
return base64.urlsafe_b64decode(s + pad)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def verify(
|
|
23
|
+
header: str,
|
|
24
|
+
key: bytes,
|
|
25
|
+
*,
|
|
26
|
+
now: float | None = None,
|
|
27
|
+
max_age: int = 120,
|
|
28
|
+
) -> dict[str, Any]:
|
|
29
|
+
"""
|
|
30
|
+
Verify an X-Trust header and return its claims.
|
|
31
|
+
|
|
32
|
+
Raises Untrusted on any failure. Never returns a payload whose
|
|
33
|
+
signature has not been verified first.
|
|
34
|
+
"""
|
|
35
|
+
if not header:
|
|
36
|
+
raise Untrusted("empty header")
|
|
37
|
+
parts = header.split(".")
|
|
38
|
+
if len(parts) != 3:
|
|
39
|
+
raise Untrusted("malformed")
|
|
40
|
+
version, payload_b64, sig_b64 = parts
|
|
41
|
+
if version != "v1":
|
|
42
|
+
raise Untrusted(f"unsupported version: {version}")
|
|
43
|
+
|
|
44
|
+
payload = _b64d(payload_b64)
|
|
45
|
+
expected = hmac.new(key, payload_b64.encode("ascii"), hashlib.sha256).digest()
|
|
46
|
+
provided = _b64d(sig_b64)
|
|
47
|
+
if not hmac.compare_digest(expected, provided):
|
|
48
|
+
raise Untrusted("bad signature")
|
|
49
|
+
|
|
50
|
+
claims = json.loads(payload) # only trusted bytes reach the parser
|
|
51
|
+
|
|
52
|
+
score = claims.get("score")
|
|
53
|
+
if not isinstance(score, (int, float)) or score < 0 or score > 1:
|
|
54
|
+
raise Untrusted("invalid score")
|
|
55
|
+
|
|
56
|
+
iat = claims.get("iat")
|
|
57
|
+
exp = claims.get("exp")
|
|
58
|
+
if not isinstance(iat, (int, float)) or not isinstance(exp, (int, float)):
|
|
59
|
+
raise Untrusted("invalid timestamps")
|
|
60
|
+
|
|
61
|
+
n = now if now is not None else time.time()
|
|
62
|
+
if n > exp:
|
|
63
|
+
raise Untrusted("expired")
|
|
64
|
+
if n - iat > max_age:
|
|
65
|
+
raise Untrusted("stale")
|
|
66
|
+
|
|
67
|
+
return claims
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: htl-verify
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Verify X-Trust signed human-presence headers. Standard library only.
|
|
5
|
+
Author-email: Dieng <diengamine.htl@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/htl-syterme/htl-core
|
|
8
|
+
Project-URL: Repository, https://github.com/htl-syterme/htl-core
|
|
9
|
+
Project-URL: Spec, https://github.com/htl-syterme/htl-core/blob/main/SPEC.md
|
|
10
|
+
Keywords: trust,human-proof,anti-bot,x-trust,llm,ai-infrastructure
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
|
|
14
|
+
Classifier: Topic :: Security
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# htl-verify
|
|
19
|
+
|
|
20
|
+
Verify X-Trust signed human-presence headers in Python. Standard library only.
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
pip install htl-verify
|
|
25
|
+
|
|
26
|
+
## Use
|
|
27
|
+
|
|
28
|
+
from htl_verify import verify, Untrusted
|
|
29
|
+
|
|
30
|
+
try:
|
|
31
|
+
claims = verify(header, key=secret_bytes)
|
|
32
|
+
score = claims["score"]
|
|
33
|
+
if score >= 0.5:
|
|
34
|
+
pass # annotated as likely-human
|
|
35
|
+
except Untrusted:
|
|
36
|
+
pass # treat as unverified; never blocks by default
|
|
37
|
+
|
|
38
|
+
## What it is not
|
|
39
|
+
|
|
40
|
+
Not a CAPTCHA, not identity, not bot authentication. The score is a signal,
|
|
41
|
+
not a proof. A determined client can raise its own score; that is a property
|
|
42
|
+
of any client-side signal and is documented in the project SPEC.
|
|
43
|
+
|
|
44
|
+
## Wire format
|
|
45
|
+
|
|
46
|
+
X-Trust: v1.<payload_b64url>.<sig_b64url>
|
|
47
|
+
|
|
48
|
+
Payload JSON: `{sub, score, iat, exp, nonce?}`. HMAC-SHA256 over the
|
|
49
|
+
base64url payload. TTL 120s. Score 0..1.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
htl_verify
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "htl-verify"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Verify X-Trust signed human-presence headers. Standard library only."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
authors = [{ name = "Dieng", email = "diengamine.htl@gmail.com" }]
|
|
13
|
+
keywords = ["trust", "human-proof", "anti-bot", "x-trust", "llm", "ai-infrastructure"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Topic :: Internet :: WWW/HTTP :: HTTP Servers",
|
|
18
|
+
"Topic :: Security",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
[project.urls]
|
|
22
|
+
Homepage = "https://github.com/htl-syterme/htl-core"
|
|
23
|
+
Repository = "https://github.com/htl-syterme/htl-core"
|
|
24
|
+
Spec = "https://github.com/htl-syterme/htl-core/blob/main/SPEC.md"
|