import os
import sys
from pathlib import Path
import urllib.parse
state_locations = [
Path('/etc/gmitodo'), # System-wide config directory
Path.home() / '.config/gmitodo', # User config directory
Path.cwd(), # Current working directory
Path('/tmp/gmitodo') # Transient directory
]
CONFIG_TEMPLATE = '''# gmitodo configuration file
auth_view=no
auth_edit=no
allow=
'''
def read_state(filename):
for location in state_locations:
try:
state_file = location / filename
data = [x for x in state_file.read_text().split('\n') if x != '']
return data
except OSError:
continue
def write_state(filename, data):
for i, line in enumerate(data):
if ' ' in line:
data[i] = urllib.parse.quote_plus(line)
for location in state_locations:
try:
location.mkdir(parents=True, exist_ok=True)
state_file = location / filename
state_file.write_text('\n'.join(data) + '\n')
return
except OSError:
continue
print('42 Unable to write state\r')
raise SystemExit
def check_auth():
if remote_addr not in allowed_users:
if cert_hash == '':
print('60 Client certificate required\r')
raise SystemExit
elif cert_hash not in allowed_users:
sys.stderr.write('certificate hash: ' + cert_hash)
print('61 Certificate not authorized\r')
raise SystemExit
server_name = os.environ['SERVER_NAME'] if 'SERVER_NAME' in os.environ else ''
path_info = os.environ['PATH_INFO'] if 'PATH_INFO' in os.environ else ''
query_string = os.environ['QUERY_STRING'].replace('/', '%2F') if 'QUERY_STRING' in os.environ else ''
remote_addr = os.environ['REMOTE_ADDR'] if 'REMOTE_ADDR' in os.environ else ''
cert_hash = os.environ['TLS_CLIENT_HASH'].lower() if 'TLS_CLIENT_HASH' in os.environ else ''
_data = read_state('todo.conf')
if _data is None:
write_state('todo.conf', [CONFIG_TEMPLATE])
_data = CONFIG_TEMPLATE.split('\n')
auth_view = False
auth_edit = False
allowed_users = []
for line in _data:
if line.startswith('auth_view='):
auth_view = True if line[10:].lower() in ['yes', '1', 'true'] else False
elif line.startswith('auth_edit='):
auth_edit = True if line[10:].lower() in ['yes', '1', 'true'] else False
elif line.startswith('allow='):
_param = line[6:].lower()
if _param != '':
allowed_users.append(_param)
if path_info == '':
if auth_view:
check_auth()
print('20 text/gemini\r')
print('=> /cgi-bin/todo/add + Add New')
print('=> /cgi-bin/todo/multiadd + Add Multiple')
print('____________________\r')
print()
for line in read_state('todo.list'):
if ' ' in line:
line = urllib.parse.quote_plus(line)
unquoted = urllib.parse.unquote_plus(line)
print('=> /cgi-bin/todo/rm?{} √ {}'.format(line, unquoted))
elif path_info == '/add' or path_info == '/multiadd':
if auth_edit:
check_auth()
if query_string == '':
print('10 Enter new entry\r')
else:
state = read_state('todo.list')
# Split input at newlines and add each as separate entries
if '\n' in query_string or ' ' in query_string:
query_string = urllib.parse.quote_plus(query_string)
for line in query_string.split('%0A'):
line = line.strip('+')
if line != '' and line not in state:
state.append(line)
write_state('todo.list', state)
if path_info == '/multiadd':
print('30 gemini://{}/cgi-bin/todo/multiadd\r'.format(server_name))
print('30 gemini://{}/cgi-bin/todo\r'.format(server_name))
elif path_info == '/rm':
if auth_edit:
check_auth()
if query_string == '':
print('59 Missing parameter\r')
else:
state = read_state('todo.list')
if query_string in state:
state.remove(query_string)
write_state('todo.list', state)
print('30 gemini://{}/cgi-bin/todo\r'.format(server_name))
else:
print('50 Not found\r')
application/octet-stream
This content has been proxied by September (3851b).