#!/usr/bin/env python3 import http.server, json, os, urllib.parse, shutil VAULT_DIR = '/opt/jarvis-vault' class VaultHandler(http.server.BaseHTTPRequestHandler): def _send(self, data, status=200): self.send_response(status) self.send_header('Content-Type', 'application/json') self.send_header('Access-Control-Allow-Origin', '*') self.send_header('Access-Control-Allow-Methods', 'GET,PUT,DELETE,OPTIONS') self.send_header('Access-Control-Allow-Headers', 'Content-Type') self.end_headers() self.wfile.write(json.dumps(data).encode()) def do_OPTIONS(self): self._send({}) def do_GET(self): parsed = urllib.parse.urlparse(self.path) params = urllib.parse.parse_qs(parsed.query) path = params.get('path', [None])[0] if parsed.path == '/tree': files = [] for root, dirs, fnames in os.walk(VAULT_DIR): for f in fnames: rel = os.path.relpath(os.path.join(root, f), VAULT_DIR) files.append(rel) self._send({'files': sorted(files)}) elif parsed.path == '/read' and path: full = os.path.join(VAULT_DIR, path) if not os.path.realpath(full).startswith(os.path.realpath(VAULT_DIR)): return self._send({'error': 'Invalid path'}, 400) if os.path.isfile(full): with open(full) as f: self._send({'path': path, 'content': f.read()}) else: self._send({'error': 'Not found'}, 404) else: self._send({'error': 'Not found'}, 404) def do_PUT(self): parsed = urllib.parse.urlparse(self.path) params = urllib.parse.parse_qs(parsed.query) path = params.get('path', [None])[0] if not path: return self._send({'error': 'Missing path'}, 400) length = int(self.headers.get('Content-Length', 0)) content = self.rfile.read(length).decode() if length else '' full = os.path.join(VAULT_DIR, path) if not os.path.realpath(full).startswith(os.path.realpath(VAULT_DIR)): return self._send({'error': 'Invalid'}, 400) os.makedirs(os.path.dirname(full), exist_ok=True) with open(full, 'w') as f: f.write(content) self._send({'saved': True}) def do_DELETE(self): parsed = urllib.parse.urlparse(self.path) params = urllib.parse.parse_qs(parsed.query) path = params.get('path', [None])[0] if not path: return self._send({'error': 'Missing path'}, 400) full = os.path.join(VAULT_DIR, path) if not os.path.realpath(full).startswith(os.path.realpath(VAULT_DIR)): return self._send({'error': 'Invalid'}, 400) if os.path.isfile(full): os.remove(full) elif os.path.isdir(full): shutil.rmtree(full) else: return self._send({'error': 'Not found'}, 404) self._send({'deleted': True}) http.server.HTTPServer(('0.0.0.0', 8801), VaultHandler).serve_forever()