torquests 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.
- torquests-1.0.0/.github/CONTRIBUTING.md +91 -0
- torquests-1.0.0/.github/SECURITY.md +61 -0
- torquests-1.0.0/LICENSE +674 -0
- torquests-1.0.0/MANIFEST.in +7 -0
- torquests-1.0.0/NOTICE +8 -0
- torquests-1.0.0/PKG-INFO +183 -0
- torquests-1.0.0/README.md +136 -0
- torquests-1.0.0/examples/README.md +17 -0
- torquests-1.0.0/examples/fetch_clearnet.py +13 -0
- torquests-1.0.0/examples/fetch_onion.py +18 -0
- torquests-1.0.0/examples/run_socks_proxy.py +15 -0
- torquests-1.0.0/examples/session_and_identity.py +19 -0
- torquests-1.0.0/pyproject.toml +126 -0
- torquests-1.0.0/setup.cfg +4 -0
- torquests-1.0.0/src/torquests/__init__.py +98 -0
- torquests-1.0.0/src/torquests/__main__.py +10 -0
- torquests-1.0.0/src/torquests/_client/__init__.py +1 -0
- torquests-1.0.0/src/torquests/_client/bootstrap.py +560 -0
- torquests-1.0.0/src/torquests/_client/config.py +21 -0
- torquests-1.0.0/src/torquests/_client/torclient.py +499 -0
- torquests-1.0.0/src/torquests/_crypto/__init__.py +6 -0
- torquests-1.0.0/src/torquests/_crypto/ed25519_blind.py +115 -0
- torquests-1.0.0/src/torquests/_crypto/primitives.py +147 -0
- torquests-1.0.0/src/torquests/_dir/__init__.py +6 -0
- torquests-1.0.0/src/torquests/_dir/authorities.py +50 -0
- torquests-1.0.0/src/torquests/_dir/consensus.py +155 -0
- torquests-1.0.0/src/torquests/_dir/dirhttp.py +136 -0
- torquests-1.0.0/src/torquests/_dir/guards.py +91 -0
- torquests-1.0.0/src/torquests/_dir/keycerts.py +102 -0
- torquests-1.0.0/src/torquests/_dir/microdesc.py +28 -0
- torquests-1.0.0/src/torquests/_dir/models.py +126 -0
- torquests-1.0.0/src/torquests/_dir/parsers.py +365 -0
- torquests-1.0.0/src/torquests/_dir/pathselect.py +238 -0
- torquests-1.0.0/src/torquests/_http/__init__.py +5 -0
- torquests-1.0.0/src/torquests/_http/connection.py +63 -0
- torquests-1.0.0/src/torquests/_http/response.py +76 -0
- torquests-1.0.0/src/torquests/_http/streamsocket.py +109 -0
- torquests-1.0.0/src/torquests/_http/tlssocket.py +109 -0
- torquests-1.0.0/src/torquests/_net/__init__.py +5 -0
- torquests-1.0.0/src/torquests/_net/channel.py +144 -0
- torquests-1.0.0/src/torquests/_net/circuit.py +368 -0
- torquests-1.0.0/src/torquests/_net/flowcontrol.py +115 -0
- torquests-1.0.0/src/torquests/_net/hop.py +40 -0
- torquests-1.0.0/src/torquests/_net/link.py +133 -0
- torquests-1.0.0/src/torquests/_net/sink.py +25 -0
- torquests-1.0.0/src/torquests/_net/stream.py +176 -0
- torquests-1.0.0/src/torquests/_net/transport.py +135 -0
- torquests-1.0.0/src/torquests/_onion/__init__.py +1 -0
- torquests-1.0.0/src/torquests/_onion/address.py +105 -0
- torquests-1.0.0/src/torquests/_onion/descriptor.py +538 -0
- torquests-1.0.0/src/torquests/_onion/hsdir.py +160 -0
- torquests-1.0.0/src/torquests/_onion/rendezvous.py +164 -0
- torquests-1.0.0/src/torquests/_proto/__init__.py +6 -0
- torquests-1.0.0/src/torquests/_proto/cells.py +229 -0
- torquests-1.0.0/src/torquests/_proto/certs.py +106 -0
- torquests-1.0.0/src/torquests/_proto/constants.py +132 -0
- torquests-1.0.0/src/torquests/_proto/handshake/__init__.py +11 -0
- torquests-1.0.0/src/torquests/_proto/handshake/hs_ntor.py +131 -0
- torquests-1.0.0/src/torquests/_proto/handshake/ntor.py +89 -0
- torquests-1.0.0/src/torquests/_proto/linkspec.py +99 -0
- torquests-1.0.0/src/torquests/_proto/relay.py +214 -0
- torquests-1.0.0/src/torquests/_proto/relay_crypto.py +110 -0
- torquests-1.0.0/src/torquests/adapter.py +176 -0
- torquests-1.0.0/src/torquests/api.py +90 -0
- torquests-1.0.0/src/torquests/cli.py +105 -0
- torquests-1.0.0/src/torquests/client.py +17 -0
- torquests-1.0.0/src/torquests/exceptions.py +184 -0
- torquests-1.0.0/src/torquests/py.typed +0 -0
- torquests-1.0.0/src/torquests/sessions.py +166 -0
- torquests-1.0.0/src/torquests/socks.py +205 -0
- torquests-1.0.0/src/torquests/stealth.py +245 -0
- torquests-1.0.0/src/torquests.egg-info/SOURCES.txt +102 -0
- torquests-1.0.0/tests/__init__.py +0 -0
- torquests-1.0.0/tests/conftest.py +53 -0
- torquests-1.0.0/tests/crypto_helpers.py +20 -0
- torquests-1.0.0/tests/dir_fixtures.py +350 -0
- torquests-1.0.0/tests/fakes.py +418 -0
- torquests-1.0.0/tests/onion_fixtures.py +389 -0
- torquests-1.0.0/tests/onion_service_fake.py +92 -0
- torquests-1.0.0/tests/test_adapter.py +287 -0
- torquests-1.0.0/tests/test_cli.py +75 -0
- torquests-1.0.0/tests/test_crypto_helpers.py +14 -0
- torquests-1.0.0/tests/test_crypto_primitives.py +135 -0
- torquests-1.0.0/tests/test_dir.py +785 -0
- torquests-1.0.0/tests/test_dir_tunnel.py +428 -0
- torquests-1.0.0/tests/test_ed25519_blind.py +105 -0
- torquests-1.0.0/tests/test_exceptions.py +45 -0
- torquests-1.0.0/tests/test_fail_loud.py +367 -0
- torquests-1.0.0/tests/test_handshake.py +126 -0
- torquests-1.0.0/tests/test_live_integration.py +199 -0
- torquests-1.0.0/tests/test_net_channel.py +146 -0
- torquests-1.0.0/tests/test_net_circuit.py +235 -0
- torquests-1.0.0/tests/test_net_link.py +79 -0
- torquests-1.0.0/tests/test_net_stream.py +141 -0
- torquests-1.0.0/tests/test_onion_address.py +106 -0
- torquests-1.0.0/tests/test_onion_v3.py +386 -0
- torquests-1.0.0/tests/test_proto_wire.py +344 -0
- torquests-1.0.0/tests/test_public_api.py +52 -0
- torquests-1.0.0/tests/test_relay_crypto.py +132 -0
- torquests-1.0.0/tests/test_rendezvous.py +188 -0
- torquests-1.0.0/tests/test_sessions.py +167 -0
- torquests-1.0.0/tests/test_socks.py +129 -0
- torquests-1.0.0/tests/test_stealth_integration.py +45 -0
- torquests-1.0.0/tests/test_torclient.py +109 -0
- torquests-1.0.0/tests/vectors/hs_ntor.json +19 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in `torquests`. This document covers the development
|
|
4
|
+
setup and the conventions the project holds to.
|
|
5
|
+
|
|
6
|
+
## Development setup
|
|
7
|
+
|
|
8
|
+
The project uses [uv](https://docs.astral.sh/uv/) for environments and
|
|
9
|
+
[ruff](https://docs.astral.sh/ruff/) + [mypy](https://mypy-lang.org/) + pytest for
|
|
10
|
+
quality gates.
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
git clone https://github.com/SafwanLjd/torquests
|
|
14
|
+
cd torquests
|
|
15
|
+
uv venv
|
|
16
|
+
uv pip install -e ".[dev]"
|
|
17
|
+
pre-commit install
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Everyday commands run the tools installed above through `uv run`:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# lint, type-check, and test -- exactly what CI runs
|
|
24
|
+
uv run ruff check src tests
|
|
25
|
+
uv run ruff format --check src tests
|
|
26
|
+
uv run mypy src
|
|
27
|
+
uv run pytest
|
|
28
|
+
|
|
29
|
+
# auto-fix lint and format in place
|
|
30
|
+
uv run ruff check --fix src tests && uv run ruff format src tests
|
|
31
|
+
|
|
32
|
+
# live-network suite (needs a reachable Tor network)
|
|
33
|
+
uv run pytest --run-integration -m integration
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Test-driven, offline-first
|
|
37
|
+
|
|
38
|
+
This is a network library, so its tests must not touch the network. The unit suite
|
|
39
|
+
runs with sockets disabled (`--disable-socket`); a layer that seems to need the
|
|
40
|
+
network to test needs a fake transport instead. The `FakeRelayTransport` in the test
|
|
41
|
+
suite performs the link handshake and the server halves of the ntor and hs-ntor
|
|
42
|
+
handshakes in process, so circuits, streams, the directory system, and the onion
|
|
43
|
+
rendezvous flow are all exercised without a live relay.
|
|
44
|
+
|
|
45
|
+
Protocol code is validated against gold vectors and generated fixtures, not
|
|
46
|
+
against a running Tor: the official hs-ntor test vectors live in
|
|
47
|
+
`tests/vectors/hs_ntor.json`, the ed25519 key-blinding regression vector is
|
|
48
|
+
inline in `tests/test_ed25519_blind.py`, and the consensus/descriptor fixtures
|
|
49
|
+
are generated by `tests/dir_fixtures.py` and `tests/onion_fixtures.py`.
|
|
50
|
+
|
|
51
|
+
Write the failing test first, then the smallest code that passes it, then refactor.
|
|
52
|
+
Do not open a pull request on a red build.
|
|
53
|
+
|
|
54
|
+
Live-network checks are marked `@pytest.mark.integration` and are skipped unless you
|
|
55
|
+
pass `--run-integration` (`uv run pytest --run-integration -m integration`). They need
|
|
56
|
+
a reachable Tor network.
|
|
57
|
+
|
|
58
|
+
## Style and scope
|
|
59
|
+
|
|
60
|
+
- Target Python 3.10+ and modern typing. Every public function is typed and
|
|
61
|
+
documented.
|
|
62
|
+
- Match the surrounding code. `ruff` and `mypy --strict` are authoritative; if they
|
|
63
|
+
pass and the tests pass, the style is right.
|
|
64
|
+
- Errors fail loud: no bare `except`, no fabricated fallbacks, no silently-truncated
|
|
65
|
+
results. Tor-specific errors subclass the matching `requests` exception.
|
|
66
|
+
- Verify protocol details against the Tor specifications and library behavior
|
|
67
|
+
against the library's own documentation. Cite the source in the code or the pull
|
|
68
|
+
request when the detail is non-obvious.
|
|
69
|
+
|
|
70
|
+
## Commits and pull requests
|
|
71
|
+
|
|
72
|
+
Keep commits small and focused. Subjects follow
|
|
73
|
+
[Conventional Commits](https://www.conventionalcommits.org): a
|
|
74
|
+
`type(scope): summary` line in the imperative mood, where `type` is one of `feat`,
|
|
75
|
+
`fix`, `docs`, `test`, `refactor`, `perf`, `build`, `ci`, or `chore`. History reads
|
|
76
|
+
as an intentional story, so squash fixups before opening a pull request.
|
|
77
|
+
|
|
78
|
+
Run `pre-commit install` once (see the setup above). On every commit the hooks run
|
|
79
|
+
`ruff` (lint and format) and a set of file-hygiene checks (trailing whitespace,
|
|
80
|
+
end-of-file, YAML and TOML validity, large files); a Conventional Commits check runs
|
|
81
|
+
on the commit message. Describe what changed and why in the pull
|
|
82
|
+
request, and note the specification section or vector a protocol change rests on. CI
|
|
83
|
+
runs lint, type-check, and the offline suite across Python 3.10 to 3.14, and all must
|
|
84
|
+
pass.
|
|
85
|
+
|
|
86
|
+
## Reporting security issues
|
|
87
|
+
|
|
88
|
+
Because this library is used for privacy, please report suspected anonymity or
|
|
89
|
+
cryptographic defects through a private GitHub Security Advisory (see
|
|
90
|
+
[SECURITY.md](SECURITY.md)) rather than a public issue, so a fix can land before the
|
|
91
|
+
details are public.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Reporting a vulnerability
|
|
4
|
+
|
|
5
|
+
Report suspected vulnerabilities privately. Do not open a public issue for a
|
|
6
|
+
security problem, and do not disclose the details publicly until a fix has shipped.
|
|
7
|
+
|
|
8
|
+
Report through **GitHub Security Advisories**: open a draft advisory at
|
|
9
|
+
https://github.com/SafwanLjd/torquests/security/advisories/new.
|
|
10
|
+
|
|
11
|
+
Please include the affected version, a description of the issue, and, where you can,
|
|
12
|
+
a minimal reproduction. This project treats anonymity and cryptographic defects as
|
|
13
|
+
security issues, not ordinary bugs, so report those through the same private channels.
|
|
14
|
+
|
|
15
|
+
Expect an acknowledgement within a few days. We will keep you informed while a fix
|
|
16
|
+
is prepared and will credit you in the advisory unless you ask otherwise. We welcome
|
|
17
|
+
good-faith research and will not pursue reporters who follow this policy.
|
|
18
|
+
|
|
19
|
+
## Supported versions
|
|
20
|
+
|
|
21
|
+
Only the latest published release receives security fixes. There are no long-term
|
|
22
|
+
support branches.
|
|
23
|
+
|
|
24
|
+
| Version | Supported |
|
|
25
|
+
| ------- | --------- |
|
|
26
|
+
| Latest release | Yes |
|
|
27
|
+
| Everything older | No |
|
|
28
|
+
|
|
29
|
+
## Anonymity limitations
|
|
30
|
+
|
|
31
|
+
torquests anonymizes the **transport**, not the application layer. It routes your
|
|
32
|
+
connection through Tor circuits and reaches v3 onion services directly, but it does
|
|
33
|
+
nothing to make the traffic it carries look like a browser's.
|
|
34
|
+
|
|
35
|
+
Understand these limits before relying on the library for anonymity:
|
|
36
|
+
|
|
37
|
+
- **The client is fingerprintable as non-browser Python.** torquests uses the
|
|
38
|
+
standard library `ssl` module for TLS and `http.client` for HTTP/1.1. Neither can
|
|
39
|
+
reproduce Tor Browser's TLS ClientHello (the cipher, extension, and curve ordering
|
|
40
|
+
that JA3/JA4 hash) or its HTTP/2 frame and header behaviour. A destination server
|
|
41
|
+
or a malicious exit relay can therefore fingerprint the client as a Python Tor
|
|
42
|
+
client rather than Tor Browser, and can distinguish it from the Tor Browser crowd.
|
|
43
|
+
- **No application-layer or browser fingerprinting defenses.** The library does not
|
|
44
|
+
address JavaScript execution, canvas or font fingerprinting, cookies, referrers,
|
|
45
|
+
redirect chains, or any of the browser-level signals that deanonymize users. What
|
|
46
|
+
your code sends in headers, request timing, and payloads is your responsibility.
|
|
47
|
+
- **No traffic-analysis or timing-correlation protection beyond what Tor circuits
|
|
48
|
+
provide.** A global adversary able to observe both ends of a circuit is outside the
|
|
49
|
+
threat model, as it is for Tor generally.
|
|
50
|
+
- **Entry guards are not persisted.** To leave no on-disk trace, the client draws a
|
|
51
|
+
fresh guard set each process rather than pinning guards across runs as Tor does, which
|
|
52
|
+
trades reduced forensic residue for more entry-guard exposure over time.
|
|
53
|
+
- **No warranty.** Do not use it where a deanonymization would put someone at risk
|
|
54
|
+
without independent review.
|
|
55
|
+
|
|
56
|
+
To blend into the Tor Browser user base on the wire, enable **stealth mode** (the
|
|
57
|
+
`torquests[stealth]` extra), which routes through curl_cffi to present a real Tor
|
|
58
|
+
Browser TLS ClientHello and HTTP/2 fingerprint over Tor. For the full browser
|
|
59
|
+
threat model (JavaScript, canvas and font fingerprinting, and the rest), use
|
|
60
|
+
[Tor Browser](https://www.torproject.org/download/) itself. torquests is built for
|
|
61
|
+
programmatic access to Tor and onion services from Python.
|