diff --git a/backend/app/api/office.py b/backend/app/api/office.py index 7962ce0..d6765e6 100644 --- a/backend/app/api/office.py +++ b/backend/app/api/office.py @@ -422,14 +422,35 @@ def onlyoffice_callback(): """Callback from OnlyOffice when document is saved.""" import urllib.request + # Validate OnlyOffice JWT token if JWT is enabled + jwt_secret = os.environ.get('JWT_SECRET_KEY', '') + if jwt_secret: + import jwt as pyjwt + auth_header = request.headers.get('Authorization', '') + if auth_header.startswith('Bearer '): + oo_token = auth_header[7:] + try: + pyjwt.decode(oo_token, jwt_secret, algorithms=['HS256']) + except Exception as e: + print(f'[OnlyOffice Callback] JWT validation failed: {e}') + return jsonify({'error': 1}), 200 + callback_key = request.args.get('key', '') file_id_str = AppSettings.get(f'oo_callback_{callback_key}', '') if not file_id_str: return jsonify({'error': 1}), 200 # OnlyOffice expects {"error": 0} for success + # OnlyOffice may wrap the body in a JWT token data = request.get_json() - status = data.get('status', 0) + if data and 'token' in data and jwt_secret: + import jwt as pyjwt + try: + data = pyjwt.decode(data['token'], jwt_secret, algorithms=['HS256']) + except Exception: + pass + + status = data.get('status', 0) if data else 0 # Status 2 = document ready for saving, 6 = force save if status in (2, 6): @@ -443,7 +464,15 @@ def onlyoffice_callback(): filepath = Path(current_app.config['UPLOAD_PATH']) / str(f.owner_id) / f.storage_path # Download the saved document from OnlyOffice - urllib.request.urlretrieve(download_url, str(filepath)) + req = urllib.request.Request(download_url) + if jwt_secret: + # OnlyOffice may require JWT for download too + import jwt as pyjwt + dl_token = pyjwt.encode({'url': download_url}, jwt_secret, algorithm='HS256') + req.add_header('Authorization', f'Bearer {dl_token}') + with urllib.request.urlopen(req) as resp, open(str(filepath), 'wb') as out: + import shutil + shutil.copyfileobj(resp, out) # Update metadata f.size = os.path.getsize(str(filepath)) @@ -455,7 +484,9 @@ def onlyoffice_callback(): f.updated_at = datetime.now(timezone.utc) db.session.commit() except Exception as e: - print(f'[OnlyOffice Callback] Error: {e}') + print(f'[OnlyOffice Callback] Save error: {e}') + import traceback + traceback.print_exc() return jsonify({'error': 1}), 200 # Status 4 = closed without changes