diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 7de0a71..2717780 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -19,16 +19,18 @@ WebDrop Bridge is a professional Qt-based desktop application (v0.5.0) that conv | File | Purpose | |------|---------| -| `src/webdrop_bridge/__init__.py` | Package info, version (0.5.0) | +| `src/webdrop_bridge/__init__.py` | Package info, version (0.7.1) | | `src/webdrop_bridge/main.py` | Application entry point, config loading | | `src/webdrop_bridge/config.py` | Configuration management (file/env), URL mappings, validation | | `src/webdrop_bridge/core/validator.py` | Path validation against whitelist, security checks | | `src/webdrop_bridge/core/drag_interceptor.py` | Drag-and-drop event handling | -| `src/webdrop_bridge/core/config_manager.py` | File-based config loading and caching | +| `src/webdrop_bridge/core/config_manager.py` | Configuration validation, profiles, import/export | | `src/webdrop_bridge/core/url_converter.py` | Azure blob URL → local path conversion | | `src/webdrop_bridge/core/updater.py` | Update checking via Forgejo API, release management | | `src/webdrop_bridge/ui/main_window.py` | Main Qt window, config injection, menu bar | | `src/webdrop_bridge/ui/restricted_web_view.py` | Hardened QWebEngineView with security policies | +| `src/webdrop_bridge/ui/bridge_script_intercept.js` | JavaScript drag interception and WebChannel bridge | +| `src/webdrop_bridge/ui/download_interceptor.js` | Download handling for web content | | `src/webdrop_bridge/ui/settings_dialog.py` | Settings UI, URL mapping configuration | | `src/webdrop_bridge/ui/update_manager_ui.py` | Update check UI and dialogs | | `src/webdrop_bridge/utils/logging.py` | Logging configuration (console + file) | @@ -254,6 +256,6 @@ git push origin feature/my-feature --- -**Current Status**: Phase 4 Complete (Jan 29, 2026) - Phase 5 (Release Candidates) Planned -**Version**: 0.5.0 -**Last Updated**: February 18, 2026 +**Current Status**: Phase 4 Complete - Phase 5 (Release Candidates) In Progress +**Version**: 0.7.1 +**Last Updated**: March 3, 2026 diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 48c4636..c1cf8be 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -36,10 +36,11 @@ **Key Components:** -- `validator.py`: Path validation against whitelist -- `drag_interceptor.py`: Drag event handling and conversion -- `config.py`: Configuration management -- `errors.py`: Custom exception classes +- `validator.py`: Path validation against whitelist with security checks +- `drag_interceptor.py`: Drag event handling and native drag operations +- `config_manager.py`: Configuration loading from files and caching +- `url_converter.py`: Azure Blob Storage URL → local path conversion +- `updater.py`: Update checking via Forgejo API **Dependencies**: None (only stdlib + pathlib) @@ -49,9 +50,12 @@ **Key Components:** -- `main_window.py`: Main application window -- `widgets.py`: Reusable custom widgets -- `styles.py`: UI styling and themes +- `main_window.py`: Main application window with web engine integration +- `restricted_web_view.py`: Hardened QWebEngineView with security policies +- `settings_dialog.py`: Settings UI for configuration +- `update_manager_ui.py`: Update checking and notification UI +- `bridge_script_intercept.js`: JavaScript drag interception and WebChannel bridge for Qt communication +- `download_interceptor.js`: Download handling for web content **Dependencies**: PySide6, core/ @@ -61,9 +65,7 @@ **Key Components:** -- `logging.py`: Logging configuration -- `constants.py`: Application constants -- `helpers.py`: General-purpose helper functions +- `logging.py`: Logging configuration (console + file with rotation) **Dependencies**: stdlib only @@ -72,34 +74,57 @@ ### Drag-and-Drop Operation ``` -User in Web App +User in Web App (browser) ↓ -[dragstart event] → JavaScript sets dataTransfer.text = "Z:\path\file.txt" +[dragstart event] → bridge_script_intercept.js detects drag + ├─ Checks if content is convertible (file path or Azure URL) + ├─ Calls window.bridge.start_file_drag(url) + └─ preventDefault() → Blocks normal browser drag + ↓ -[dragend event] → Drag leaves WebEngine widget +JavaScript → QWebChannel Bridge ↓ -DragInterceptor.dragEnterEvent() triggered +_DragBridge.start_file_drag(path_text) [main_window.py] + ├─ Defers execution via QTimer (drag manager safety) + └─ Calls DragInterceptor.handle_drag() + ↓ -Extract text from QMimeData +DragInterceptor.handle_drag() [core/drag_interceptor.py] + ├─ Check if Azure URL: Use URLConverter → local path + ├─ Else: Treat as direct file path + └─ Validate with PathValidator + ↓ -PathValidator.is_valid_file(path) - ├─ is_allowed(path) → Check whitelist - └─ path.exists() and path.is_file() → File system check +PathValidator.validate(path) + ├─ Resolve to absolute path + ├─ Check file exists (if configured) + ├─ Check is regular file (not directory) + └─ Check path within allowed_roots (whitelist) + ↓ If valid: → Create QUrl.fromLocalFile(path) - → Create new QMimeData with URLs - → QDrag.exec() → Native file drag + → Create QMimeData with file URL + → QDrag.exec(Qt.CopyAction) → Native file drag + → Emit drag_started signal ↓ If invalid: - → event.ignore() - → Log warning + → Emit drag_failed signal with error + → Log validation error ↓ OS receives native file drag ↓ -InDesign/Word receives file handle +Target application (InDesign/Word) receives file handle ``` +**Key Components in Data Flow:** + +1. **bridge_script_intercept.js**: Opens a WebChannel to Qt's _DragBridge +2. **_DragBridge**: Exposes `start_file_drag()` slot to JavaScript +3. **DragInterceptor**: Handles validation and native drag creation +4. **URLConverter**: Maps Azure Blob Storage URLs to local paths via config +5. **PathValidator**: Security-critical validation against whitelist + ## Security Model ### Path Validation Strategy diff --git a/docs/CONFIGURATION_BUILD.md b/docs/CONFIGURATION_BUILD.md index c9d1212..d69abfa 100644 --- a/docs/CONFIGURATION_BUILD.md +++ b/docs/CONFIGURATION_BUILD.md @@ -12,7 +12,7 @@ The configuration file must be named `.env` and contains settings like: ```dotenv APP_NAME=WebDrop Bridge -APP_VERSION=0.1.0 +APP_VERSION=0.7.1 WEBAPP_URL=https://example.com ALLOWED_ROOTS=Z:/,C:/Users/Public ALLOWED_URLS= diff --git a/docs/DRAG_DROP_PROBLEM_ANALYSIS.md b/docs/DRAG_DROP_PROBLEM_ANALYSIS.md index 7e6906d..1219a8c 100644 --- a/docs/DRAG_DROP_PROBLEM_ANALYSIS.md +++ b/docs/DRAG_DROP_PROBLEM_ANALYSIS.md @@ -1,8 +1,28 @@ # Drag & Drop Problem Analysis - File Drop + Web App Popup -## Das Kernproblem +**Status**: Phase 1 (File Drop) ✅ Implemented | Phase 2 (Popup Trigger) ⏸️ Planned +**Last Updated**: March 3, 2026 -**Ziel**: Bei ALT-Drag soll: +## Overview + +### Current Implementation Status + +✅ **Phase 1 - File Drop (IMPLEMENTED)** +- JavaScript in `bridge_script_intercept.js` intercepts drag events +- Calls `window.bridge.start_file_drag(url)` via QWebChannel to Qt +- Validates path against whitelist via `PathValidator` +- Converts Azure Storage URLs to local paths via `URLConverter` +- Creates and executes native Qt file drag operation +- Target application (InDesign, Word, etc.) successfully receives file + +⏸️ **Phase 2 - Programmatic Popup Trigger (PLANNED)** +- Would require reverse-engineering the web app's popup trigger mechanism +- Could be implemented by calling JavaScript function after successful drop +- Currently: Applications handle popups manually or separately from file drops + +--- + +## Das Kernproblem 1. ✅ File gedroppt werden (Z:\ Laufwerk) → Native File-Drop 2. ✅ Web-App Popup erscheinen (Auschecken-Dialog) → Web-App Drop-Event @@ -250,28 +270,39 @@ Object.defineProperty(DataTransfer.prototype, 'types', { ## 📝 Empfehlung -**Sofortige Maßnahmen:** +### Current Status (as of March 2026) -1. ✅ **Lösung A Phase 1 ist bereits implementiert** (File-Drop funktioniert) +✅ **Phase 1 Complete:** +- File-drop via native Qt drag operations is fully functional +- JavaScript bridge (`bridge_script_intercept.js`) successfully intercepts and converts drags +- Path validation and Azure URL mapping working +- Tested with real applications (InDesign, Word, etc.) -2. 🔍 **Reverse-Engineering durchführen:** - - GlobalDAM JRI im Browser öffnen - - DevTools öffnen (F12) - - ALT-Drag+Drop durchführen - - Beobachten: - - Network-Tab → API-Calls? - - Console → Fehler/Logs? - - Angular DevTools → Component-Events? +### For Future Enhancement (Phase 2 - Popup Trigger) -3. 🛠️ **Popup-Trigger implementieren:** - - Sobald bekannt WIE Popup ausgelöst wird - - JavaScript-Funktion `trigger_checkout_popup()` erstellen - - Von Qt aus nach erfolgreichem Drop aufrufen +**If popup trigger integration is needed:** -4. 🧪 **Testen:** - - ALT-Drag eines Assets - - File-Drop sollte funktionieren - - Popup sollte erscheinen +1. 🔍 **Reverse-Engineering the Target Web App:** + - Identify how popups are triggered (API call, component method, event, etc.) + - Use browser DevTools: + - Network tab → Monitor API calls + - Console → Check for JavaScript errors/logs + - Elements → Inspect component structure + - Angular/Vue DevTools if applicable -**Fallback:** -Falls Reverse-Engineering zu komplex ist → **Lösung B** verwenden (Kein Drag, nur Copy nach Popup-Bestätigung) +2. 🛠️ **Implement Popup Trigger:** + - Create JavaScript hook function (e.g., `window.trigger_popup(assetId)`) + - Connect to drop success signal from Qt + - Call popup trigger after successful file drop + +3. 🧪 **Test Integration:** + - Verify file drops successfully + - Verify popup appears after drop + - Test with real assets/files + +**Alternative Approaches:** + +- **Lösung B (Manual)**: Keep file drop and popup as separate user actions +- **Lösung C (Complex)**: Use overlay window approach (more involved) + +Current implementation uses **Phase 1 of Lösung A** and is production-ready.