gemini.git

going-flying.com gemini git repository

summary

tree

log

refs

c1f88f146e3384d471d41000051bf68842a3eb9b - Matthew Ernisse - 1649440419

use my own gemini client now

view tree

view raw

diff --git a/build/build.py b/build/build.py
index e4baa6e..8f80025 100755
--- a/build/build.py
+++ b/build/build.py
@@ -1,7 +1,34 @@
 #!/usr/bin/env python3
-
+''' build.py (c) 2020-2022 Matthew J. Ernisse <matt@going-flying.com>
+All Rights Reserved.
+
+Redistribution and use in source and binary forms,
+with or without modification, are permitted provided
+that the following conditions are met:
+
+    * Redistributions of source code must retain the
+      above copyright notice, this list of conditions
+      and the following disclaimer.
+    * Redistributions in binary form must reproduce
+     the above copyright notice, this list of conditions
+      and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'''
 import datetime
 import feedparser
+import gemini
 import jinja2
 import os
 import pytz
@@ -11,9 +38,6 @@ import sys
 from feedgen.feed import FeedGenerator
 from urllib.parse import quote_plus as quote
 
-sys.path.append('/var/gemini/capcom')
-import gusmobile
-
 URLBASE = 'gemini://going-flying.com/~mernisse/'
 
 
@@ -261,11 +285,12 @@ if __name__ == '__main__':
 	if not feed.should_notify():
 		sys.exit()
 
-	myurl = quote('gemini://going-flying.com/~mernisse/atom.xml')
+	print('Trying to notify Antenna')
 
-	# gusmobile has a bug where it needs the port in the URL I guess.
-	url = 'gemini://warmedal.se:1965/~antenna/submit'
-	# resp = gusmobile.fetch(f'{url}?{myurl}')
-	# if not resp.status == 20:
-	# 	print('Failed to notify Antenna')
-	print(f'Would call {url}?{myurl}')
+	try:
+		resp = gemini.fetch(
+			'gemini://warmedal.se/~antenna/submit'
+			query='gemini://going-flying.com/~mernisse/atom.xml'
+		)
+	except Exception as e:
+		print(f'Failed to notify Antenna {e!s}')
diff --git a/build/gemini.py b/build/gemini.py
new file mode 100644
index 0000000..3993861
--- /dev/null
+++ b/build/gemini.py
@@ -0,0 +1,158 @@
+''' gemini.py (c) 2022 Matthew J. Ernisse <matt@going-flying.com>
+All Rights Reserved.
+
+Redistribution and use in source and binary forms,
+with or without modification, are permitted provided
+that the following conditions are met:
+
+    * Redistributions of source code must retain the
+      above copyright notice, this list of conditions
+      and the following disclaimer.
+    * Redistributions in binary form must reproduce
+     the above copyright notice, this list of conditions
+      and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+'''import certifi
+import select
+import socket
+import ssl
+import urllib.parse as urlparse
+
+
+CHUNK_SIZE = 1024
+GEMINI_TIMEOUT = 15.0
+
+class GEMINIError(Exception):
+	''' Exception raised when a server returns an error condition,
+	either temporary or permanent.  The code is stored as the
+	code property.
+	'''
+	def __init__(self, message, code=None):
+		super().__init__(message)
+		self.code = code
+
+
+class Response(object):
+	''' Hold a Gemini response. '''
+	def __init__(self, url):
+		self.url = url
+
+	def set_data(self, data):
+		self.content_type = 'text/gemini'
+		self.data = data
+		self.text = data.decode('utf-8')
+	
+		self.meta = self.text.split('\r\n', 1)[0]
+		self.code = int(self.meta[0:2])
+
+		self.meta = self.meta.split(None, 1)[1]
+
+		if self.code == 20:
+			self.content_type = self.meta
+
+		elif self.code >= 40 and self.code < 60:
+			raise GEMINIError(self.meta, self.code)
+
+		elif self.code >= 60:
+			raise Exception('Not Implemented.')
+
+	def is_redirect(self):
+		if self.code >= 30 and self.code < 40:
+			return True
+
+		return False
+
+	def is_ok(self):
+		if self.code > 30:
+			return False
+
+		return True
+
+
+def request(url, **kwargs):
+	''' Perform a Gemini request.  The following
+	keyword arguments are supported:
+
+	query - Append as a query parameter.  Will be
+		url encoded prior to sending.  Defaults
+		to nothing.
+
+	verify - Verify the TLS certificate chain presented.
+		This is often not possible with Gemini's use
+		of self signed certificates (unfortunatly)
+		so it defaults to False.
+	'''
+
+	query = kwargs.get('query', None)
+	verify = kwargs.get('verify', False)
+
+	parts = urlparse.urlparse(url)
+	if not parts:
+		raise ValueError(f'{url} is not a valid url.')
+
+	if not parts.scheme == 'gemini':
+		raise ValueError(f'{url} not a gemini url')
+
+
+	host = parts.netloc
+	port = 1965
+
+	if ':' in host:
+		(host, port) = host.split(':')
+
+	ctx = ssl.create_default_context()
+	ctx.minimum_version = ssl.TLSVersion.TLSv1_2
+
+	if not verify:
+		ctx.check_hostname = False
+		ctx.verify_mode = ssl.CERT_NONE
+	else:
+		ctx.load_verify_locations(certifi.where())
+
+	request = url
+	if query:
+		request += f'?{urlparse.quote(query)}'
+
+	request += '\r\n'
+	request = request.encode('utf-8')
+	if len(request) > 1024:
+		raise ValueError('Encoded request is over 1024 bytes')
+
+	response = Response(url)
+	response.request = request
+
+	socket.setdefaulttimeout(GEMINI_TIMEOUT)
+
+	with socket.create_connection((host, port)) as sock:
+		with ctx.wrap_socket(sock, server_hostname=host) as tlssock:
+
+			response.tls_cipher = tlssock.cipher()
+			response.tls_version = tlssock.version()
+			# This will be nothing if verify is false.
+			response.tls_certificate = tlssock.getpeercert()
+
+			tlssock.sendall(request)
+
+			data = tlssock.recv(CHUNK_SIZE)
+			while True:
+				chunk = tlssock.recv(CHUNK_SIZE)
+				data += chunk
+
+				if len(chunk) < CHUNK_SIZE:
+					break
+	
+			response.set_data(data)
+
+	return response
diff --git a/files/thoughts-to-gemini.py b/files/thoughts-to-gemini.py
index 7015a21..a6b919a 100755
--- a/files/thoughts-to-gemini.py
+++ b/files/thoughts-to-gemini.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 # -*- coding: UTF-8 -*-
-'''thoughts-to-gemini.py (c) 2020-2021 Matthew J Ernisse <matt@going-flying.com>
+'''thoughts-to-gemini.py (c) 2020-2022 Matthew J Ernisse <matt@going-flying.com>
 All Rights Reserved.
 
 Redistribution and use in source and binary forms,
@@ -77,7 +77,7 @@ index_template = '''```
 # 🕰️ Generated at {{ build_time }}
 
 
-🚀 © MMXX-MMXXI matt@going-flying.com 
+🚀 © MMXX-MMXXII matt@going-flying.com 
 '''
 
 URLBASE = 'gemini://going-flying.com/thoughts/'
diff --git a/index.gmi b/index.gmi
index bd88ca5..38c8ad7 100644
--- a/index.gmi
+++ b/index.gmi
@@ -64,4 +64,4 @@ And of course, we wouldn't be here without the project itself.
 
 => gemini://gemini.circumlunar.space	Obligatory Gemini Information Link
 
-🚀 © MMXX-MMXXI matt@going-flying.com 
+🚀 © MMXX-MMXXII matt@going-flying.com