=> 1e13c94ae4967b6676007027a922d7e88874a20c
[1mdiff --git a/README.md b/README.md[m [1mindex 6c04597..fbccb70 100644[m [1m--- a/README.md[m [1m+++ b/README.md[m [36m@@ -7,7 +7,7 @@[m [mThis is a simple Python script that listens for Titan requests and then adds, up[m The configuration file _~/.booster/config.json_ must exist:[m [m ```json[m [31m-{ [m [32m+[m[32m{[m "python": "/usr/bin/python3",[m "git": {[m "exec": "/usr/bin/git",[m [36m@@ -18,8 +18,15 @@[m [mThe configuration file _~/.booster/config.json_ must exist:[m "cert": "/absolute-path/titan.crt",[m "key": "/absolute-path/titan.key",[m "authorized": "/absolute-path/titan-clients.pem",[m [31m- "file_root": "/absolute-path-where-files-are-kept/",[m "site_url": "gemini://skyjake.fi",[m [31m- "root": "/gemlog"[m [32m+[m[32m "files": {[m [32m+[m[32m "root": "/absolute-path/capsule-files/",[m [32m+[m[32m "Gemlog": {[m [32m+[m[32m "subdir": "gemlog/"[m [32m+[m[32m },[m [32m+[m[32m "Title prefix for Git": {[m [32m+[m[32m "file": "relative-path-of-single-file.gmi"[m [32m+[m[32m }[m [32m+[m[32m }[m }[m ```[m [1mdiff --git a/booster.py b/booster.py[m [1mindex d4e9d09..a2636da 100755[m [1m--- a/booster.py[m [1m+++ b/booster.py[m [36m@@ -30,11 +30,15 @@[m # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE[m # POSSIBILITY OF SUCH DAMAGE.[m [m [31m-import os, sys, json, subprocess[m [32m+[m[32mimport os, sys, json, subprocess, time[m import socket, ssl, OpenSSL.crypto, hashlib[m from urllib.parse import urlparse[m pjoin = os.path.join[m [m [32m+[m[32mdef append_slash(p):[m [32m+[m[32m if not p.endswith('/'): return p + '/'[m [32m+[m[32m return p[m [32m+[m #----------------------------------------------------------------------------#[m # CONFIGURATION #[m #----------------------------------------------------------------------------#[m [36m@@ -45,9 +49,8 @@[m [mif not os.path.exists(CFG_PATH):[m print(f'ERROR: Configuration file {CFG_PATH} not found.')[m sys.exit(1)[m CONFIG = json.loads(open(CFG_PATH, 'rt').read())[m [31m-if not CONFIG['root'].endswith('/'):[m [31m- CONFIG['root'] = CONFIG['root'] + '/'[m print(json.dumps(CONFIG, indent=2))[m [32m+[m[32mFILES_ROOT = append_slash(CONFIG['files']['root'])[m [m #----------------------------------------------------------------------------#[m # REQUEST HANDLING #[m [36m@@ -75,6 +78,7 @@[m [mdef urlenc(q):[m return q[m [m def handle_client(stream):[m [32m+[m[32m print(time.strftime('%Y-%m-%d %H:%M:%S'))[m data = bytes()[m incoming = stream.recv(1024)[m expected_size = -1[m [36m@@ -105,54 +109,81 @@[m [mdef handle_client(stream):[m if len(data) >= expected_size:[m break[m incoming = stream.recv(1024)[m [31m- # process the request[m [32m+[m print(f'URL : {req_url}')[m print(f'Token : {req_token}')[m print(f'MIME : {req_mime}')[m print(f'Data : {len(data)} bytes')[m [32m+[m parts = urlparse(req_url)[m path = parts.path[m [31m- if not path.startswith(CONFIG['root']):[m [31m- report_error(stream, 51, "invalid path")[m [31m- return[m [31m- path = path[len(CONFIG['root']):][m [31m- if path.startswith('.'):[m [32m+[m[32m file_path = None[m [32m+[m[32m msg_path = None[m [32m+[m[32m if (path.startswith('.') or[m [32m+[m[32m os.path.basename(path).startswith('.') or[m [32m+[m[32m '..' in path):[m report_error(stream, 61, "access is not authorized")[m return[m [31m- file_path = pjoin(CONFIG['file_root'], path)[m [31m- view_url = '%s/%s%s' % (CONFIG['site_url'], CONFIG['root'], path)[m [32m+[m [32m+[m[32m # Are we allowed to edit this path?[m [32m+[m[32m msg_prefix = ''[m [32m+[m[32m for file_group in CONFIG['files']:[m [32m+[m[32m group = CONFIG['files'][file_group][m [32m+[m[32m if type(group) != dict: continue[m [32m+[m[32m if 'subdir' in group:[m [32m+[m[32m auth_prefix = append_slash(group['subdir'])[m [32m+[m[32m msg_path = path[len(auth_prefix):][m [32m+[m[32m elif 'file' in group:[m [32m+[m[32m auth_prefix = '/' + group['file'][m [32m+[m[32m msg_path = os.path.basename(path)[m [32m+[m[32m if path.startswith(auth_prefix):[m [32m+[m[32m file_path = os.path.normpath(FILES_ROOT + path)[m [32m+[m[32m if not file_path.startswith(FILES_ROOT) or \[m [32m+[m[32m os.path.isdir(file_path):[m [32m+[m[32m report_error(stream, 61, "access is not authorized")[m [32m+[m[32m return[m [32m+[m[32m msg_prefix = f'{file_group}: '[m [32m+[m[32m break[m [32m+[m[32m if not file_path:[m [32m+[m[32m report_error(stream, 61, "unauthorized location")[m [32m+[m[32m return[m [32m+[m [32m+[m[32m # Process the request.[m [32m+[m[32m is_new = not os.path.exists(file_path)[m [32m+[m[32m view_url = '%s%s' % (CONFIG['site_url'], path)[m response = '# Booster log\n'[m [31m- is_new = not os.path.exists(file_path)[m [31m- GIT = CONFIG['git'][m if not is_new and req_token == 'DELETE':[m response += f'* deleting file: {file_path}\n'[m os.remove(file_path)[m [31m- git_msg = GIT['message_prefix'] + 'Removed ' + path[m [32m+[m[32m git_msg = msg_prefix + 'Removed ' + msg_path[m else:[m if is_new:[m response += f'* creating a new file: {file_path}\n'[m [31m- git_msg = GIT['message_prefix'] + 'Added ' + path[m [32m+[m[32m git_msg = msg_prefix + 'Added ' + msg_path[m else:[m response += f'* updating file: {file_path}\n'[m [31m- git_msg = GIT['message_prefix'] + 'Updated ' + path[m [32m+[m[32m git_msg = msg_prefix + 'Updated ' + msg_path[m # write the data[m response += f'* writing %d bytes\n' % len(data)[m dst = open(file_path, 'wb')[m dst.write(data)[m dst.close()[m [31m- # update indices[m [31m- os.chdir(CONFIG['file_root'])[m [32m+[m [32m+[m[32m # Update Gemlog indices.[m [32m+[m[32m GEMLOG_SUBDIR = CONFIG['files']['Gemlog']['subdir'][m [32m+[m[32m os.chdir(pjoin(FILES_ROOT, GEMLOG_SUBDIR))[m response += f'* updating indices\n'[m response += run_command([CONFIG['python'], ".makeindex.py"])[m response += '* committing changes to Git repository\n'[m if is_new:[m [31m- response += run_command([GIT['exec'], 'add', file_path])[m [31m- response += run_command([GIT['exec'], 'commit', '-a', '-m', git_msg])[m [32m+[m[32m response += run_command([CONFIG['git'], 'add', file_path])[m [32m+[m[32m response += run_command([CONFIG['git'], 'commit', '-a', '-m', git_msg])[m response += "\n"[m response += f"=> {view_url} View the page\n"[m response += f"=> gemini://warmedal.se/~antenna/submit?%s Notify Antenna" %\[m [31m- urlenc('%s%s' % (CONFIG['site_url'], CONFIG['root']))[m [31m- # compose a response[m [32m+[m[32m urlenc('%s%s' % (CONFIG['site_url'], GEMLOG_SUBDIR))[m [32m+[m [32m+[m[32m # Send the response.[m stream.sendall(('20 text/gemini; charset=utf-8\r\n%s' %[m response).encode('utf-8'))[m [m
text/gemini; charset=utf-8
This content has been proxied by September (ba2dc).