fix: OnlyOffice Callback JWT-Validierung + Speichern

Problem: OnlyOffice sendete JWT-Token im Callback-Request und im
Body, unser Endpoint hat das ignoriert -> Speichern schlug fehl.

Fix:
- Callback validiert OnlyOffice JWT aus Authorization-Header
- Callback entpackt JWT-wrapped Body (OnlyOffice wraps den Body
  in einen JWT-Token wenn JWT_ENABLED=true)
- Download der gespeicherten Datei sendet JWT-Header mit
- Besseres Error-Logging mit Traceback

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Stefan Hacker 2026-04-11 22:28:34 +02:00
parent 1f9b87900c
commit 9d1f4e117c
1 changed files with 34 additions and 3 deletions

View File

@ -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