diff options
Diffstat (limited to 'ophiculus/ophiculus.py')
-rwxr-xr-x | ophiculus/ophiculus.py | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/ophiculus/ophiculus.py b/ophiculus/ophiculus.py new file mode 100755 index 0000000..af145e8 --- /dev/null +++ b/ophiculus/ophiculus.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 +import socket +import ssl +import sys +import urllib.parse + +# read target url from arguments +arg = sys.argv[1] +if '//' not in arg: + arg = '//' + arg + +url = urllib.parse.urlparse(arg, scheme='gemini') +if url.scheme != 'gemini': + sys.exit('Unable to handle scheme') + +port = url.port if url.port is not None else 1965 +context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) +context.options |= OP_NO_TLSv1 | OP_NO_TLSV1_1 | OP_NO_TLSv1_2 +# ignore certs for now, TODO actually handle cert TOFU +context.check_hostname = False +context.verify_mode = ssl.CERT_NONE + +# TODO AF_INET6 support +with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: + with context.wrap_socket(sock, server_hostname=url.hostname) as ssock: + # connect to server [TLS handshake occurs after connect() by default] + ip = socket.gethostbyname(url.hostname) + ssock.connect((ip, port)) + ssock.sendall(urlparse.urlunsplit(url) + '\r\n') + + with ssock.makefile() as io: + header = io.readline() + print(header) + status, meta = header.split(' ', 1) + switch = status[0] + if switch == '1': + query = urllib.parse.quote(input('server requesting input: ' + meta)) + # TODO retry request + else if switch == '2': + # meta is mime type + # TODO handle text/gemini i guess? + if meta.startswith('text/'): + body = io.read() + for line in body.spiltlines(): + print(line) + else: + # TODO download file instead + sys.exit('didn\'t get a text file') + else if switch == '3': + print('temporary redirect to: ' + meta) + # TODO prompt to follow + else if switch == '4': + print('temporary failure: ' + meta) + else if switch == '5': + print('permanent failure: ' + meta) + else if switch == '6': + print('client certificate required: ' + meta) + # TODO prompt to retry + else: + print('unknown response: ' + meta) |