neptls 0.1.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.
neptls-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Diwas Khatri
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
neptls-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,180 @@
1
+ Metadata-Version: 2.4
2
+ Name: neptls
3
+ Version: 0.1.0
4
+ Summary: A dependency-light HTTP client and TLS research toolkit for authorized testing.
5
+ Author-email: Diwas Khatri <diwaskhatri07@users.noreply.github.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/diwaskhatri07/neptls
8
+ Project-URL: Repository, https://github.com/diwaskhatri07/neptls
9
+ Project-URL: Issues, https://github.com/diwaskhatri07/neptls/issues
10
+ Keywords: http,tls,networking,diagnostics,fingerprinting
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3 :: Only
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Internet :: WWW/HTTP
20
+ Classifier: Topic :: Security
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Dynamic: license-file
25
+
26
+ # NepTLS
27
+
28
+ NepTLS is a dependency-light Python HTTP client and TLS research toolkit. It
29
+ combines a requests-style API with structured TLS configuration, browser
30
+ network profiles, local fingerprint analysis, diagnostics, pools, and a
31
+ generic proof-of-work framework.
32
+
33
+ **Developed by Diwas Khatri (@diwaskhatri07).**
34
+
35
+ ## Security boundary
36
+
37
+ NepTLS is for networking research, browser compatibility, API testing,
38
+ protocol interoperability, performance testing, debugging, authorized
39
+ automation, and defensive security research. It is not designed to bypass
40
+ CAPTCHAs, authentication, payment security, access controls, or anti-abuse
41
+ systems, and it does not include session theft or credential attack features.
42
+ Fingerprint objects describe and compare configurations; they do not spoof
43
+ browser security signals.
44
+
45
+ ## Installation
46
+
47
+ ```bash
48
+ python -m pip install neptls
49
+ ```
50
+
51
+ NepTLS has no runtime dependencies and supports Python 3.10+.
52
+
53
+ ## Quick start
54
+
55
+ ```python
56
+ import neptls
57
+
58
+ response = neptls.get("https://example.com", timeout=10)
59
+ response.raise_for_status()
60
+ print(response.status_code)
61
+ print(response.text[:80])
62
+ ```
63
+
64
+ Reusable clients retain cookies and configuration:
65
+
66
+ ```python
67
+ client = neptls.Client(
68
+ profile="chrome",
69
+ headers={"X-Research-Client": "neptls"},
70
+ retries=2,
71
+ )
72
+
73
+ response = client.post("https://httpbin.org/post", json={"hello": "world"})
74
+ print(response.json())
75
+ ```
76
+
77
+ Async calls use the same public API:
78
+
79
+ ```python
80
+ import asyncio
81
+ from neptls import AsyncClient
82
+
83
+ async def main():
84
+ async with AsyncClient(timeout=10) as client:
85
+ response = await client.get("https://example.com")
86
+ print(response.status_code)
87
+
88
+ asyncio.run(main())
89
+ ```
90
+
91
+ ## TLS and profiles
92
+
93
+ `TLSConfig` creates standard-library `ssl.SSLContext` objects and can be
94
+ serialized for experiments:
95
+
96
+ ```python
97
+ from neptls import TLSConfig, TLSFingerprint
98
+
99
+ config = TLSConfig(minimum_version="TLSv1.2", alpn_protocols=("h2", "http/1.1"))
100
+ print(config.to_json())
101
+ print(TLSFingerprint.from_config(config).digest)
102
+ ```
103
+
104
+ Profiles are structured metadata, not browser impersonation:
105
+
106
+ ```python
107
+ client = neptls.Client(profile="firefox")
108
+ print(client.fingerprint().to_dict())
109
+ print(neptls.profiles.get_profile("chrome").to_json())
110
+ ```
111
+
112
+ ## Fingerprints and user agents
113
+
114
+ ```python
115
+ profile = neptls.fingerprint.generate(browser="chrome", platform="windows", seed=7)
116
+ print(profile.validate().to_json())
117
+ print(neptls.ua.chrome())
118
+ print(neptls.user_agents.parse(neptls.ua.random()))
119
+ ```
120
+
121
+ The built-in user-agent catalog is intentionally curated. Load a properly
122
+ licensed dataset into `UserAgentDatabase` when your application needs a
123
+ larger pool; NepTLS does not bundle a copied 40,000-entry third-party list.
124
+
125
+ ## Diagnostics
126
+
127
+ `inspect()` performs read-only DNS, TCP, TLS, and HTTP observations:
128
+
129
+ ```python
130
+ report = neptls.inspect("https://example.com")
131
+ print(report["tls"]["version"])
132
+ ```
133
+
134
+ ## Pools, proxies, hashing, and generic PoW
135
+
136
+ ```python
137
+ from neptls import Proxy
138
+ from neptls.crypto import sha256
139
+ from neptls.pools import Pool
140
+ from neptls.pow import Challenge, solve
141
+
142
+ pool = Pool(["profile-a", "profile-b"])
143
+ print(pool.next())
144
+ client = neptls.Client(proxy="http://127.0.0.1:8080")
145
+ print(sha256("protocol message"))
146
+ result = solve(Challenge("demo", difficulty=3))
147
+ ```
148
+
149
+ The PoW implementation is generic and intentionally not tied to any
150
+ anti-abuse or security system.
151
+
152
+ ## CLI
153
+
154
+ ```bash
155
+ neptls version
156
+ neptls get https://example.com
157
+ neptls inspect https://example.com
158
+ neptls profile chrome
159
+ neptls ua mobile
160
+ neptls hash "protocol message" --algorithm sha256
161
+ neptls pow demo --difficulty 3
162
+ ```
163
+
164
+ ## Development
165
+
166
+ ```bash
167
+ python -m unittest discover -s tests -v
168
+ python -m compileall -q src
169
+ python -m build
170
+ ```
171
+
172
+ The project is organized into focused modules for HTTP transport, TLS models,
173
+ profiles, fingerprints, user agents, pools, proxy data, diagnostics, crypto,
174
+ PoW, and the CLI. Features that depend on native HTTP/2 or HTTP/3 stacks are
175
+ kept out of the initial dependency-free release until their transport and
176
+ platform behavior can be tested reliably.
177
+
178
+ ## License and credits
179
+
180
+ NepTLS is released under the MIT License. See `LICENSE`.
neptls-0.1.0/README.md ADDED
@@ -0,0 +1,155 @@
1
+ # NepTLS
2
+
3
+ NepTLS is a dependency-light Python HTTP client and TLS research toolkit. It
4
+ combines a requests-style API with structured TLS configuration, browser
5
+ network profiles, local fingerprint analysis, diagnostics, pools, and a
6
+ generic proof-of-work framework.
7
+
8
+ **Developed by Diwas Khatri (@diwaskhatri07).**
9
+
10
+ ## Security boundary
11
+
12
+ NepTLS is for networking research, browser compatibility, API testing,
13
+ protocol interoperability, performance testing, debugging, authorized
14
+ automation, and defensive security research. It is not designed to bypass
15
+ CAPTCHAs, authentication, payment security, access controls, or anti-abuse
16
+ systems, and it does not include session theft or credential attack features.
17
+ Fingerprint objects describe and compare configurations; they do not spoof
18
+ browser security signals.
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ python -m pip install neptls
24
+ ```
25
+
26
+ NepTLS has no runtime dependencies and supports Python 3.10+.
27
+
28
+ ## Quick start
29
+
30
+ ```python
31
+ import neptls
32
+
33
+ response = neptls.get("https://example.com", timeout=10)
34
+ response.raise_for_status()
35
+ print(response.status_code)
36
+ print(response.text[:80])
37
+ ```
38
+
39
+ Reusable clients retain cookies and configuration:
40
+
41
+ ```python
42
+ client = neptls.Client(
43
+ profile="chrome",
44
+ headers={"X-Research-Client": "neptls"},
45
+ retries=2,
46
+ )
47
+
48
+ response = client.post("https://httpbin.org/post", json={"hello": "world"})
49
+ print(response.json())
50
+ ```
51
+
52
+ Async calls use the same public API:
53
+
54
+ ```python
55
+ import asyncio
56
+ from neptls import AsyncClient
57
+
58
+ async def main():
59
+ async with AsyncClient(timeout=10) as client:
60
+ response = await client.get("https://example.com")
61
+ print(response.status_code)
62
+
63
+ asyncio.run(main())
64
+ ```
65
+
66
+ ## TLS and profiles
67
+
68
+ `TLSConfig` creates standard-library `ssl.SSLContext` objects and can be
69
+ serialized for experiments:
70
+
71
+ ```python
72
+ from neptls import TLSConfig, TLSFingerprint
73
+
74
+ config = TLSConfig(minimum_version="TLSv1.2", alpn_protocols=("h2", "http/1.1"))
75
+ print(config.to_json())
76
+ print(TLSFingerprint.from_config(config).digest)
77
+ ```
78
+
79
+ Profiles are structured metadata, not browser impersonation:
80
+
81
+ ```python
82
+ client = neptls.Client(profile="firefox")
83
+ print(client.fingerprint().to_dict())
84
+ print(neptls.profiles.get_profile("chrome").to_json())
85
+ ```
86
+
87
+ ## Fingerprints and user agents
88
+
89
+ ```python
90
+ profile = neptls.fingerprint.generate(browser="chrome", platform="windows", seed=7)
91
+ print(profile.validate().to_json())
92
+ print(neptls.ua.chrome())
93
+ print(neptls.user_agents.parse(neptls.ua.random()))
94
+ ```
95
+
96
+ The built-in user-agent catalog is intentionally curated. Load a properly
97
+ licensed dataset into `UserAgentDatabase` when your application needs a
98
+ larger pool; NepTLS does not bundle a copied 40,000-entry third-party list.
99
+
100
+ ## Diagnostics
101
+
102
+ `inspect()` performs read-only DNS, TCP, TLS, and HTTP observations:
103
+
104
+ ```python
105
+ report = neptls.inspect("https://example.com")
106
+ print(report["tls"]["version"])
107
+ ```
108
+
109
+ ## Pools, proxies, hashing, and generic PoW
110
+
111
+ ```python
112
+ from neptls import Proxy
113
+ from neptls.crypto import sha256
114
+ from neptls.pools import Pool
115
+ from neptls.pow import Challenge, solve
116
+
117
+ pool = Pool(["profile-a", "profile-b"])
118
+ print(pool.next())
119
+ client = neptls.Client(proxy="http://127.0.0.1:8080")
120
+ print(sha256("protocol message"))
121
+ result = solve(Challenge("demo", difficulty=3))
122
+ ```
123
+
124
+ The PoW implementation is generic and intentionally not tied to any
125
+ anti-abuse or security system.
126
+
127
+ ## CLI
128
+
129
+ ```bash
130
+ neptls version
131
+ neptls get https://example.com
132
+ neptls inspect https://example.com
133
+ neptls profile chrome
134
+ neptls ua mobile
135
+ neptls hash "protocol message" --algorithm sha256
136
+ neptls pow demo --difficulty 3
137
+ ```
138
+
139
+ ## Development
140
+
141
+ ```bash
142
+ python -m unittest discover -s tests -v
143
+ python -m compileall -q src
144
+ python -m build
145
+ ```
146
+
147
+ The project is organized into focused modules for HTTP transport, TLS models,
148
+ profiles, fingerprints, user agents, pools, proxy data, diagnostics, crypto,
149
+ PoW, and the CLI. Features that depend on native HTTP/2 or HTTP/3 stacks are
150
+ kept out of the initial dependency-free release until their transport and
151
+ platform behavior can be tested reliably.
152
+
153
+ ## License and credits
154
+
155
+ NepTLS is released under the MIT License. See `LICENSE`.
@@ -0,0 +1,47 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "neptls"
7
+ version = "0.1.0"
8
+ description = "A dependency-light HTTP client and TLS research toolkit for authorized testing."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = "MIT"
12
+ authors = [{ name = "Diwas Khatri", email = "diwaskhatri07@users.noreply.github.com" }]
13
+ keywords = ["http", "tls", "networking", "diagnostics", "fingerprinting"]
14
+ classifiers = [
15
+ "Development Status :: 3 - Alpha",
16
+ "Intended Audience :: Developers",
17
+ "Programming Language :: Python :: 3",
18
+ "Programming Language :: Python :: 3 :: Only",
19
+ "Programming Language :: Python :: 3.10",
20
+ "Programming Language :: Python :: 3.11",
21
+ "Programming Language :: Python :: 3.12",
22
+ "Programming Language :: Python :: 3.13",
23
+ "Topic :: Internet :: WWW/HTTP",
24
+ "Topic :: Security",
25
+ ]
26
+ dependencies = []
27
+
28
+ [project.urls]
29
+ Homepage = "https://github.com/diwaskhatri07/neptls"
30
+ Repository = "https://github.com/diwaskhatri07/neptls"
31
+ Issues = "https://github.com/diwaskhatri07/neptls/issues"
32
+
33
+ [project.scripts]
34
+ neptls = "neptls.cli:main"
35
+
36
+ [tool.setuptools]
37
+ package-dir = { "" = "src" }
38
+
39
+ [tool.setuptools.packages.find]
40
+ where = ["src"]
41
+
42
+ [tool.setuptools.package-data]
43
+ neptls = ["py.typed"]
44
+
45
+ [tool.ruff]
46
+ line-length = 100
47
+ target-version = "py310"
neptls-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,52 @@
1
+ """NepTLS: an HTTP client and TLS research toolkit.
2
+
3
+ Developed by Diwas Khatri (@diwaskhatri07).
4
+ """
5
+
6
+ from .async_client import AsyncClient
7
+ from .client import Client, delete, get, head, options, patch, post, put, request
8
+ from .diagnostics import diagnose, inspect
9
+ from .exceptions import HTTPStatusError, NepTLSError, RequestError, TimeoutError
10
+ from .fingerprints import ClientFingerprint
11
+ from .models import RequestTiming, Response
12
+ from .profiles import BrowserProfile, PROFILES, get_profile
13
+ from .proxy import Proxy
14
+ from .tls import TLSConfig, TLSFingerprint
15
+ from . import crypto, fingerprints as fingerprint, profiles, pow, user_agents
16
+ from .user_agents import ua
17
+
18
+ __version__ = "0.1.0"
19
+
20
+ __all__ = [
21
+ "AsyncClient",
22
+ "BrowserProfile",
23
+ "Client",
24
+ "ClientFingerprint",
25
+ "HTTPStatusError",
26
+ "NepTLSError",
27
+ "PROFILES",
28
+ "Proxy",
29
+ "RequestError",
30
+ "RequestTiming",
31
+ "Response",
32
+ "TLSConfig",
33
+ "TLSFingerprint",
34
+ "TimeoutError",
35
+ "crypto",
36
+ "delete",
37
+ "diagnose",
38
+ "fingerprint",
39
+ "get",
40
+ "get_profile",
41
+ "head",
42
+ "inspect",
43
+ "options",
44
+ "patch",
45
+ "post",
46
+ "pow",
47
+ "profiles",
48
+ "put",
49
+ "request",
50
+ "ua",
51
+ "user_agents",
52
+ ]
@@ -0,0 +1,3 @@
1
+ from .cli import main
2
+
3
+ raise SystemExit(main())
@@ -0,0 +1,52 @@
1
+ """Async API backed by the same tested synchronous transport."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ from typing import Any
7
+
8
+ from .client import Client
9
+ from .models import Response
10
+
11
+
12
+ class AsyncClient:
13
+ """An asyncio-friendly client with a persistent cookie/profile session."""
14
+
15
+ def __init__(self, **kwargs: Any) -> None:
16
+ self._client = Client(**kwargs)
17
+
18
+ async def request(self, method: str, url: str, **kwargs: Any) -> Response:
19
+ return await asyncio.to_thread(self._client.request, method, url, **kwargs)
20
+
21
+ async def get(self, url: str, **kwargs: Any) -> Response:
22
+ return await self.request("GET", url, **kwargs)
23
+
24
+ async def post(self, url: str, **kwargs: Any) -> Response:
25
+ return await self.request("POST", url, **kwargs)
26
+
27
+ async def put(self, url: str, **kwargs: Any) -> Response:
28
+ return await self.request("PUT", url, **kwargs)
29
+
30
+ async def patch(self, url: str, **kwargs: Any) -> Response:
31
+ return await self.request("PATCH", url, **kwargs)
32
+
33
+ async def delete(self, url: str, **kwargs: Any) -> Response:
34
+ return await self.request("DELETE", url, **kwargs)
35
+
36
+ async def head(self, url: str, **kwargs: Any) -> Response:
37
+ return await self.request("HEAD", url, **kwargs)
38
+
39
+ async def options(self, url: str, **kwargs: Any) -> Response:
40
+ return await self.request("OPTIONS", url, **kwargs)
41
+
42
+ def fingerprint(self):
43
+ return self._client.fingerprint()
44
+
45
+ async def close(self) -> None:
46
+ await asyncio.to_thread(self._client.close)
47
+
48
+ async def __aenter__(self) -> "AsyncClient":
49
+ return self
50
+
51
+ async def __aexit__(self, *_: object) -> None:
52
+ await self.close()
@@ -0,0 +1,76 @@
1
+ """Command-line interface for NepTLS."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import json
7
+ import sys
8
+ from dataclasses import asdict
9
+
10
+ from . import __version__, get, profiles, ua
11
+ from .crypto import blake2, md5, sha256, sha512
12
+ from .diagnostics import inspect
13
+ from .pow import Challenge, solve
14
+
15
+
16
+ def _parser() -> argparse.ArgumentParser:
17
+ parser = argparse.ArgumentParser(prog="neptls", description="NepTLS networking research toolkit")
18
+ sub = parser.add_subparsers(dest="command")
19
+ for method in ("get", "post", "put", "patch", "delete", "head", "options"):
20
+ command = sub.add_parser(method, help=f"perform an HTTP {method.upper()} request")
21
+ command.add_argument("url")
22
+ command.add_argument("--json", dest="json_body", help="JSON request body")
23
+ command.add_argument("--header", action="append", default=[], metavar="NAME:VALUE")
24
+ for name in ("inspect", "diagnose"):
25
+ command = sub.add_parser(name, help="inspect DNS, TCP, TLS, and HTTP")
26
+ command.add_argument("url")
27
+ command.add_argument("--json", action="store_true", dest="as_json")
28
+ sub.add_parser("version")
29
+ profile_command = sub.add_parser("profile", help="list browser profiles")
30
+ profile_command.add_argument("name", nargs="?")
31
+ ua_command = sub.add_parser("ua", help="query the user-agent catalog")
32
+ ua_command.add_argument("kind", nargs="?", default="random", choices=("random", "chrome", "firefox", "mobile"))
33
+ hash_command = sub.add_parser("hash", help="hash text")
34
+ hash_command.add_argument("value")
35
+ hash_command.add_argument("--algorithm", choices=("sha256", "sha512", "blake2", "md5"), default="sha256")
36
+ pow_command = sub.add_parser("pow", help="solve a generic proof-of-work challenge")
37
+ pow_command.add_argument("payload")
38
+ pow_command.add_argument("--difficulty", type=int, default=4)
39
+ return parser
40
+
41
+
42
+ def main(argv: list[str] | None = None) -> int:
43
+ args = _parser().parse_args(argv)
44
+ if args.command == "version":
45
+ print(__version__)
46
+ return 0
47
+ if args.command in {"get", "post", "put", "patch", "delete", "head", "options"}:
48
+ headers = dict(item.split(":", 1) for item in args.header if ":" in item)
49
+ body = json.loads(args.json_body) if args.json_body else None
50
+ response = getattr(__import__("neptls"), args.command)(args.url, headers=headers, json=body)
51
+ print(response.text)
52
+ return 0 if response.ok else 1
53
+ if args.command in {"inspect", "diagnose"}:
54
+ print(json.dumps(inspect(args.url), indent=2, default=str))
55
+ return 0
56
+ if args.command == "profile":
57
+ value = profiles.PROFILES if not args.name else profiles.get_profile(args.name).to_dict()
58
+ print(json.dumps(value, indent=2, default=str))
59
+ return 0
60
+ if args.command == "ua":
61
+ print(getattr(ua, args.kind)())
62
+ return 0
63
+ if args.command == "hash":
64
+ function = {"sha256": sha256, "sha512": sha512, "blake2": blake2, "md5": md5}[args.algorithm]
65
+ print(function(args.value))
66
+ return 0
67
+ if args.command == "pow":
68
+ result = solve(Challenge(args.payload, difficulty=args.difficulty))
69
+ print(json.dumps(asdict(result), default=str))
70
+ return 0
71
+ _parser().print_help()
72
+ return 0
73
+
74
+
75
+ if __name__ == "__main__":
76
+ sys.exit(main())