diff --git a/__pycache__/vault-api.cpython-313.pyc b/__pycache__/vault-api.cpython-313.pyc new file mode 100644 index 0000000..2641d2b Binary files /dev/null and b/__pycache__/vault-api.cpython-313.pyc differ diff --git a/vault-api.py b/vault-api.py new file mode 100644 index 0000000..175fee3 --- /dev/null +++ b/vault-api.py @@ -0,0 +1,71 @@ +#!/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()