modified: .gitignore

modified:   app.py
	new file:   command_storage/.gitignore
This commit is contained in:
SimolZimol
2026-01-07 04:24:59 +01:00
parent 6d38651305
commit 404b2ac77f
3 changed files with 42 additions and 24 deletions

3
.gitignore vendored
View File

@@ -3,6 +3,9 @@ __pycache__/
*.py[cod]
*$py.class
# Command storage (temporary files)
command_storage/*.json
# Virtual environments
.venv/
venv/

58
app.py
View File

@@ -8,18 +8,22 @@ from flask import Flask, render_template, jsonify, send_from_directory, request
app = Flask(__name__)
# In-memory storage for commands (thread-safe)
command_storage = {}
# File-based storage for commands (works across multiple workers)
STORAGE_DIR = Path(__file__).parent / 'command_storage'
STORAGE_DIR.mkdir(exist_ok=True)
storage_lock = Lock()
def cleanup_expired_commands():
"""Remove expired commands from storage"""
with storage_lock:
now = datetime.now(timezone.utc)
expired_keys = [key for key, value in command_storage.items()
if datetime.fromisoformat(value['expires_at']) < now]
for key in expired_keys:
del command_storage[key]
"""Remove expired command files"""
now = datetime.now(timezone.utc)
for file_path in STORAGE_DIR.glob('*.json'):
try:
with open(file_path, 'r') as f:
data = json.load(f)
if datetime.fromisoformat(data['expires_at']) < now:
file_path.unlink()
except:
pass # Ignore corrupted files
# Load projects from version.json
def load_projects():
@@ -272,13 +276,18 @@ def store_command():
created_at = datetime.now(timezone.utc)
expires_at = created_at + timedelta(minutes=30)
# Store command
# Prepare data
command_data = {
'command': command,
'created_at': created_at.isoformat(),
'expires_at': expires_at.isoformat()
}
# Store to file
storage_file = STORAGE_DIR / f'{command_uuid}.json'
with storage_lock:
command_storage[command_uuid] = {
'command': command,
'created_at': created_at.isoformat(),
'expires_at': expires_at.isoformat()
}
with open(storage_file, 'w', encoding='utf-8') as f:
json.dump(command_data, f)
# Generate URL - use HTTPS if behind proxy
scheme = request.headers.get('X-Forwarded-Proto', 'https' if request.is_secure else 'http')
@@ -300,20 +309,23 @@ def retrieve_command(command_uuid):
"""Retrieve stored command by UUID (JSON response for plugin)"""
cleanup_expired_commands()
# Keep lock for entire operation to prevent race conditions
with storage_lock:
command_data = command_storage.get(command_uuid)
storage_file = STORAGE_DIR / f'{command_uuid}.json'
if not command_data:
return jsonify({'error': 'Command not found or expired'}), 404
if not storage_file.exists():
return jsonify({'error': 'Command not found or expired'}), 404
try:
with open(storage_file, 'r', encoding='utf-8') as f:
command_data = json.load(f)
# Check if expired
if datetime.fromisoformat(command_data['expires_at']) < datetime.now(timezone.utc):
del command_storage[command_uuid]
storage_file.unlink()
return jsonify({'error': 'Command expired'}), 410
# Return a copy to avoid modification outside lock
return jsonify(dict(command_data)), 200
return jsonify(command_data), 200
except Exception as e:
return jsonify({'error': 'Failed to read command'}), 500
# Serve /versions as JSON
@app.route('/versions')

3
command_storage/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
# This directory stores temporary command data
# Files are automatically deleted after 30 minutes
*.json