-
Notifications
You must be signed in to change notification settings - Fork 14
/
jetforce_client.py
executable file
·71 lines (57 loc) · 2.25 KB
/
jetforce_client.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#!/usr/bin/env python3
"""
A very basic gemini client to use for testing server configurations.
"""
import argparse
import socket
import ssl
import sys
import typing
import urllib.parse
context = ssl.create_default_context()
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
def fetch(
url: str,
host: typing.Optional[str] = None,
port: typing.Optional[int] = None,
use_sni: bool = False,
) -> None:
parsed_url = urllib.parse.urlparse(url)
if not parsed_url.scheme:
parsed_url = urllib.parse.urlparse(f"gemini://{url}")
host = host or parsed_url.hostname
port = port or parsed_url.port or 1965
sni = host if use_sni else None
with socket.create_connection((host, port)) as sock:
with context.wrap_socket(sock, server_hostname=sni) as ssock:
ssock.sendall((url + "\r\n").encode())
fp = ssock.makefile("rb", buffering=0)
data = fp.read(1024)
while data:
sys.stdout.buffer.write(data)
sys.stdout.buffer.flush()
data = fp.read(1024)
def run_client() -> None:
# fmt: off
parser = argparse.ArgumentParser(description="A simple gemini client")
parser.add_argument("url")
parser.add_argument("--host", help="Server host")
parser.add_argument("--port", help="Server port")
parser.add_argument("--tls-certfile", help="Client certificate")
parser.add_argument("--tls-keyfile", help="Client private key")
parser.add_argument("--tls-alpn-protocol", help="Protocol for ALPN negotiation")
parser.add_argument("--tls-enable-sni", action="store_true", help="Specify the hostname using SNI")
parser.add_argument("--tls-keylog", help="Keylog file for TLS debugging (requires python 3.8+)")
# fmt: on
args = parser.parse_args()
if args.tls_certfile:
context.load_cert_chain(args.tls_certfile, args.tls_keyfile)
if args.tls_alpn_protocol:
context.set_alpn_protocols([args.tls_alpn_protocol])
if args.tls_keylog:
# This is a "private" variable that the stdlib exposes for debugging
context.keylog_filename = args.tls_keylog # type: ignore
fetch(args.url, args.host, args.port, args.tls_enable_sni)
if __name__ == "__main__":
run_client()