|
@@ -8,36 +8,43 @@ import ssl
|
|
|
urllib.parse.uses_relative.append("gemini")
|
|
|
urllib.parse.uses_netloc.append("gemini")
|
|
|
|
|
|
-class GeminiClient():
|
|
|
- def __init__(self):
|
|
|
- pass # later, TOFU tracking can be added via instantiation of the GeminiClient object
|
|
|
-
|
|
|
- def request(self,url):
|
|
|
- parsed = urllib.parse.urlparse(url)
|
|
|
- addresses = socket.getaddrinfo(parsed.hostname, parsed.port or 1965, family=0, type=socket.SOCK_STREAM)
|
|
|
-
|
|
|
- # We don't do the CA cert verification
|
|
|
- # We could implement it later but for now we won't
|
|
|
- context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
|
|
+# If we want to keep an SSL context for some time, we need to instantiate this...
|
|
|
+
|
|
|
+# Methods:
|
|
|
+# - request(url, optionally a client cert, optionally server cert)
|
|
|
+# - returns a response object: { status, meta, mimetype, body (byte array), servercert }
|
|
|
+#
|
|
|
+# - response(socket, status, meta, optionally body (byte array) )
|
|
|
+# - returns success or failure?
|
|
|
+#
|
|
|
+# - genCert(...)
|
|
|
+# - returns a cert (string?)
|
|
|
+class ResponseObject():
|
|
|
+ def __init__(self, serverCert, statusCode, metaField, mimeType, messageBody = ""):
|
|
|
+ self.serverCert = serverCert
|
|
|
+ self.statusCode = statusCode
|
|
|
+ self.metaField = metaField
|
|
|
+ self.mimeType = mimeType
|
|
|
+ self.messageBody = messageBody
|
|
|
+
|
|
|
+def request(url, clientCert = "", clientKey = "", serverCert = ""):
|
|
|
+ parsed = urllib.parse.urlparse(url)
|
|
|
+
|
|
|
+ context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
|
|
+ context.minimum_version = ssl.TLSVersion.TLSv1_2
|
|
|
+
|
|
|
+ if clientCert and clientKey:
|
|
|
+ context.load_cert_chain(clientCert, clientKey)
|
|
|
+
|
|
|
+ if serverCert:
|
|
|
+ context.load_verify_locations(serverCert)
|
|
|
+ else:
|
|
|
context.check_hostname = False
|
|
|
context.verify_mode = ssl.CERT_NONE
|
|
|
- context.minimum_version = ssl.TLSVersion.TLSv1_2
|
|
|
-
|
|
|
- for address in addresses:
|
|
|
- s = socket.socket(address[0], address[1])
|
|
|
- s.settimeout(30)
|
|
|
- s = context.wrap_socket(s, server_hostname = parsed.netloc)
|
|
|
- try:
|
|
|
- s.connect(address[4])
|
|
|
- break
|
|
|
- except OSError as e:
|
|
|
- err = e
|
|
|
- else:
|
|
|
- # If we couldn't connect to *any* of the addresses, just
|
|
|
- # bubble up the exception from the last attempt and deny
|
|
|
- # knowledge of earlier failures.
|
|
|
- raise err
|
|
|
-
|
|
|
- s.sendall((url+"\r\n").encode("UTF-8"))
|
|
|
- return s.makefile(mode = "rb")
|
|
|
+
|
|
|
+ sock = socket.create_connection((parsed.hostname, parsed.port or 1965))
|
|
|
+ ssock = context.wrap_socket(sock, server_hostname=parsed.hostname)
|
|
|
+ ssock.sendall((url+"\r\n").encode("UTF-8"))
|
|
|
+
|
|
|
+ return ssock.makefile(mode = "rb")
|
|
|
|