diff --git a/browser-extension/PERMISSIONS.md b/browser-extension/PERMISSIONS.md index d499169d..5e21fbf7 100644 --- a/browser-extension/PERMISSIONS.md +++ b/browser-extension/PERMISSIONS.md @@ -7,10 +7,10 @@ This document explains the permissions requested by the DocuElevate browser exte The extension requests the following permissions in `manifest.json`: ### activeTab -- **Purpose**: Get the URL of the currently active tab -- **Usage**: When you click the extension icon, it reads the current tab's URL to display in the popup -- **Privacy**: Only accesses the active tab when you explicitly open the popup -- **Alternative**: Without this, the extension couldn't show you which file you're sending +- **Purpose**: Get the URL and content of the currently active tab +- **Usage**: When you click the extension icon, it reads the current tab's URL and content for clipping +- **Privacy**: Only accesses the active tab when you explicitly use the extension +- **Alternative**: Without this, the extension couldn't show you which file you're sending or clip pages ### storage - **Purpose**: Save your configuration (server URL and session cookie) @@ -19,61 +19,80 @@ The extension requests the following permissions in `manifest.json`: - **Alternative**: Without this, you'd need to reconfigure the extension every time ### contextMenus -- **Purpose**: Add "Send to DocuElevate" to the right-click menu -- **Usage**: Creates a context menu item for quick access -- **Privacy**: No data access; only adds a menu item +- **Purpose**: Add context menu options for sending URLs and clipping pages +- **Usage**: Creates context menu items for quick access (Send URL, Clip Full Page, Clip Selection) +- **Privacy**: No data access; only adds menu items - **Alternative**: Without this, you'd only have the toolbar icon ### notifications - **Purpose**: Show success/error notifications -- **Usage**: Displays browser notifications when files are sent successfully or errors occur +- **Usage**: Displays browser notifications when files are sent or clipped successfully, or when errors occur - **Privacy**: Only shows notifications based on your actions - **Alternative**: Without this, you wouldn't get feedback from context menu actions -## No Host Permissions +### scripting (New in v1.1.0) +- **Purpose**: Inject content capture code into web pages for clipping +- **Usage**: When you click "Clip Page" or "Clip Selection", this permission allows the extension to execute code that captures page HTML +- **Privacy**: Code only executes when you explicitly clip a page; no tracking or monitoring +- **Scope**: Only runs in the active tab, only when you trigger clipping +- **Alternative**: Without this, web page clipping wouldn't be possible -The extension has an **empty `host_permissions` array** (`[]`). +## Host Permissions (v1.1.0) -### Why Empty? +### - Required for Web Clipping -- **Privacy-First**: The extension doesn't request blanket access to all websites -- **User-Controlled**: You configure the DocuElevate server URL, not us -- **Minimal Permissions**: Only accesses the server you explicitly configure -- **Dynamic Access**: API requests are made from popup/background scripts, not from web pages +**Why Required**: The `` host permission is necessary for the web clipping feature to work on any website you visit. -### How It Works +**Specific Use Cases**: +1. **Page Content Capture**: To clip a web page, the extension must access the page's HTML and CSS +2. **PDF Conversion**: The browser's printToPDF API requires host permissions to convert page content +3. **Dynamic Content**: Ensures clipped pages include all styles and content, regardless of the website -1. You configure your DocuElevate server URL in the extension -2. The extension stores this URL in local storage -3. When you send a file, the extension makes a direct API request to your configured server -4. No need for static host permissions because the extension doesn't inject scripts or modify web pages +**Security Safeguards**: +- **User-Initiated Only**: Content access only happens when you explicitly click "Clip Page" or "Clip Selection" +- **No Automatic Access**: The extension doesn't monitor or track your browsing +- **Local Processing**: Page content is captured and converted to PDF locally in your browser +- **No Third-Party Transmission**: Content goes only to your configured DocuElevate server +- **Temporary Access**: Content is processed immediately and not stored by the extension -### Comparison to Other Extensions +**Alternative Options**: +- **activeTab Only**: If you only want URL sending (not web clipping), the extension could work with just `activeTab` permission +- **Manual Permission**: You could be prompted per-site, but this would be cumbersome for frequent use -Many similar extensions request: -- ❌ `""` or `"*://*/*"` - Access to all websites -- ❌ `"http://*/*"` and `"https://*/*"` - Access to all HTTP/HTTPS sites - -DocuElevate requests: -- ✅ `[]` - No blanket host permissions -- ✅ Only access to your configured server (via fetch API) +**Privacy Guarantee**: Even with ``, the extension: +- Does NOT monitor your browsing +- Does NOT collect page content automatically +- Does NOT track which sites you visit +- Only accesses content when you explicitly clip a page ## Permission Justification | Permission | Required? | Justification | |------------|-----------|---------------| -| activeTab | ✅ Yes | Must read current tab URL to send files | +| activeTab | ✅ Yes | Must read current tab URL and content | | storage | ✅ Yes | Must save configuration to function | | contextMenus | ⚠️ Optional | Nice to have for quick access | | notifications | ⚠️ Optional | Nice to have for feedback | +| scripting | ✅ Yes (for clipping) | Required to capture page content for web clipping | +| host_permissions: | ✅ Yes (for clipping) | Required for web clipping to work on any website | ## Security Benefits -1. **No Web Page Access**: Extension can't read or modify content on websites you visit -2. **No Browsing History**: Extension doesn't track your browsing -3. **No Cross-Site Access**: Extension only talks to your configured server -4. **User-Controlled**: All communication is initiated by you -5. **Transparent**: All code is visible in the extension folder +1. **User-Initiated Access**: Extension only accesses page content when you explicitly click "Clip" +2. **Local Processing**: Pages converted to PDF in your browser, not on a server +3. **User-Controlled Server**: Extension only talks to your configured DocuElevate server +4. **No Automatic Tracking**: Extension doesn't monitor your browsing or collect data in the background +5. **Transparent Code**: All code is visible in the extension folder for audit + +## How Web Clipping Works Securely + +1. **You Trigger**: You click "Clip Page" or "Clip Selection" +2. **Content Capture**: Extension captures page HTML (only when you click) +3. **Local Conversion**: Your browser converts HTML to PDF using built-in API +4. **Direct Upload**: PDF is sent only to your configured DocuElevate server +5. **Temporary Tab**: A hidden tab is created temporarily for PDF conversion, then immediately closed + +**No data leaves your machine except to your own DocuElevate server.** ## How to Verify Permissions @@ -93,31 +112,35 @@ DocuElevate requests: ## Reducing Permissions Further -If you want even fewer permissions: +If you want fewer permissions or don't need web clipping: -1. **Remove contextMenus**: Delete the `contextMenus` permission from `manifest.json` - - Trade-off: Lose right-click menu option +1. **Disable Web Clipping**: Use v1.0.0 instead of v1.1.0 + - No scripting permission + - No host_permissions () + - Trade-off: Can only send URLs, not clip pages + +2. **Remove contextMenus**: Delete the `contextMenus` permission from `manifest.json` + - Trade-off: Lose right-click menu options - You'd only have the toolbar icon -2. **Remove notifications**: Delete the `notifications` permission +3. **Remove notifications**: Delete the `notifications` permission - Trade-off: No success/error notifications - You'd only see status in the popup -3. **Remove content script**: Delete the `content_scripts` section - - Trade-off: None (it's not actively used currently) - - Reduces extension footprint slightly - ## Privacy Statement -The DocuElevate browser extension: +The DocuElevate browser extension (v1.1.0): - ✅ Does NOT collect any personal data - ✅ Does NOT track your browsing history +- ✅ Does NOT monitor web pages you visit - ✅ Does NOT send data to third parties -- ✅ Does NOT modify web page content +- ✅ Does NOT modify web page content (except when you explicitly clip) - ✅ Does NOT inject ads or tracking scripts +- ✅ Only accesses page content when you explicitly click "Clip" - ✅ Only communicates with YOUR configured DocuElevate server - ✅ Stores configuration locally on your device only +- ✅ Converts pages to PDF locally in your browser ## Questions? @@ -126,7 +149,8 @@ If you have concerns about permissions or privacy, please: - Review the source code in the `browser-extension` folder - Open an issue on [GitHub](https://github.com/christianlouis/DocuElevate/issues) - Check the [Browser Extension Guide](../docs/BrowserExtension.md) +- Use v1.0.0 if you don't need web clipping features --- -Last updated: 2024 +Last updated: 2024 (v1.1.0) diff --git a/browser-extension/scripts/background.js b/browser-extension/scripts/background.js index e06b5c9d..8a7acf55 100644 --- a/browser-extension/scripts/background.js +++ b/browser-extension/scripts/background.js @@ -152,7 +152,9 @@ async function convertHtmlToPdf(html) { chrome.tabs.onUpdated.addListener(listener); }); - // Give it a bit more time to render + // Wait for page to fully render before PDF conversion + // This delay ensures JavaScript execution, dynamic content rendering, + // and CSS transitions have completed. May need adjustment for complex pages. await new Promise(resolve => setTimeout(resolve, 500)); // Use Chrome's print to PDF API diff --git a/browser-extension/scripts/capture.js b/browser-extension/scripts/capture.js index ea6b249a..d67cbc95 100644 --- a/browser-extension/scripts/capture.js +++ b/browser-extension/scripts/capture.js @@ -6,9 +6,6 @@ * @returns {Object} Page data with HTML, title, and URL */ function captureFullPage() { - // Clone the document to avoid modifying the original - const clonedDoc = document.cloneNode(true); - // Get all stylesheets and inline them const styles = Array.from(document.styleSheets) .map(sheet => { @@ -24,9 +21,6 @@ function captureFullPage() { }) .join('\n'); - // Get page HTML - const html = document.documentElement.outerHTML; - // Create a complete HTML document with inlined styles const styledHtml = ` @@ -65,28 +59,6 @@ function captureSelection() { const container = document.createElement('div'); container.appendChild(range.cloneContents()); - // Get computed styles for the selection - const styles = []; - const elements = container.querySelectorAll('*'); - elements.forEach(el => { - const computed = window.getComputedStyle(el); - // Only preserve essential styles - const essentialStyles = [ - 'font-family', 'font-size', 'font-weight', 'color', - 'background-color', 'text-align', 'margin', 'padding' - ]; - let styleStr = ''; - essentialStyles.forEach(prop => { - const value = computed.getPropertyValue(prop); - if (value) { - styleStr += `${prop}: ${value}; `; - } - }); - if (styleStr) { - el.setAttribute('style', styleStr); - } - }); - const html = ` @@ -121,51 +93,7 @@ function captureSelection() { }; } -/** - * Take a screenshot of the visible viewport - * @returns {Promise} Data URL of the screenshot - */ -async function captureScreenshot() { - // This will be called from the background script - // since content scripts can't use chrome.tabs.captureVisibleTab - return new Promise((resolve, reject) => { - chrome.runtime.sendMessage( - { type: 'CAPTURE_SCREENSHOT' }, - response => { - if (response.success) { - resolve(response.dataUrl); - } else { - reject(new Error(response.error)); - } - } - ); - }); -} - -// Listen for capture requests from popup or background -chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { - if (message.type === 'CAPTURE_FULL_PAGE') { - try { - const pageData = captureFullPage(); - sendResponse({ success: true, data: pageData }); - } catch (error) { - sendResponse({ success: false, error: error.message }); - } - return true; - } - - if (message.type === 'CAPTURE_SELECTION') { - try { - const selectionData = captureSelection(); - sendResponse({ success: true, data: selectionData }); - } catch (error) { - sendResponse({ success: false, error: error.message }); - } - return true; - } -}); - -// Export functions for use in tests or other scripts +// Export functions for use in other scripts if (typeof module !== 'undefined' && module.exports) { module.exports = { captureFullPage, diff --git a/browser-extension/scripts/content.js b/browser-extension/scripts/content.js index 83ba0562..3c315066 100644 --- a/browser-extension/scripts/content.js +++ b/browser-extension/scripts/content.js @@ -113,12 +113,13 @@ function captureSelection() { // Message handler chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { if (message.type === 'GET_PAGE_INFO') { - // Return information about the current page + // Return information about the current page (synchronous) const pageInfo = { url: window.location.href, title: document.title }; sendResponse(pageInfo); + return false; // Synchronous response, no need to keep channel open } if (message.type === 'CAPTURE_FULL_PAGE') { @@ -128,7 +129,7 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { } catch (error) { sendResponse({ success: false, error: error.message }); } - return true; + return true; // Keep channel open for async response } if (message.type === 'CAPTURE_SELECTION') { @@ -138,7 +139,7 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { } catch (error) { sendResponse({ success: false, error: error.message }); } - return true; + return true; // Keep channel open for async response } }); diff --git a/browser-extension/test.html b/browser-extension/test.html index 96efd4aa..791ffcc4 100644 --- a/browser-extension/test.html +++ b/browser-extension/test.html @@ -3,7 +3,7 @@ - Browser Extension Test Page + Browser Extension Test Page - Web Clipping

🧪 DocuElevate Browser Extension Test Page

-

How to Test

+

How to Test (v1.1.0 - Web Clipping)

  1. Make sure the DocuElevate browser extension is installed and configured
  2. -
  3. Test Method 1: Click the extension icon and send the current page URL
  4. -
  5. Test Method 2: Right-click on any link below and select "Send to DocuElevate"
  6. -
  7. Test Method 3: Navigate to a link below and then use the extension popup
  8. +
  9. URL Mode: Click extension icon, select "Send URL" mode, click "Send to DocuElevate"
  10. +
  11. Clip Full Page: Click extension icon, select "Clip Page" mode, click "Clip Full Page"
  12. +
  13. Clip Selection: Select text below, click extension icon, click "Clip Selection"
  14. +
  15. Context Menu - URL: Right-click page and select "Send URL to DocuElevate"
  16. +
  17. Context Menu - Full: Right-click page and select "Clip Full Page to DocuElevate"
  18. +
  19. Context Menu - Selection: Select text, right-click, select "Clip Selection to DocuElevate"
-

📄 Sample Document Links

+

📄 Sample Document Links (URL Mode)

These links point to sample documents that can be processed by DocuElevate:

-

🖼️ Sample Image Links

+

🖼️ Sample Image Links (URL Mode)

These links point to sample images that can be processed:

-

✅ Expected Behavior

+

📝 Selectable Content for Clip Testing

+

Use this content to test the selection clipping feature:

+ +
+

Important Document

+

This is a sample paragraph that you can select and clip to DocuElevate. + Select this text with your mouse, then right-click and choose "Clip Selection to DocuElevate" from the context menu.

+ +

Key Points:

+
    +
  • Web clipping allows you to save any web content as PDF
  • +
  • You can clip full pages or just selected portions
  • +
  • Pages are converted to PDF in your browser before upload
  • +
  • All styling and formatting is preserved
  • +
+ +

This content will be captured with its styling and converted to a PDF document that's sent to DocuElevate for processing!

+
+
+ +
+

✅ Expected Behavior (v1.1.0)

+

URL Mode:

    -
  • Extension Popup: Should show the current page URL and allow sending it
  • -
  • Context Menu: Right-click should show "Send to DocuElevate" option
  • -
  • Success Notification: Browser notification with task ID should appear
  • -
  • Error Handling: Clear error messages if something goes wrong
  • +
  • Extension Popup: Shows "Send URL" mode with current page URL
  • +
  • Context Menu: "Send URL to DocuElevate" option appears
  • +
  • Success: Notification with task ID appears
  • +
+ +

Clip Mode:

+
    +
  • Extension Popup: Shows "Clip Page" mode with two buttons
  • +
  • Full Page: Captures entire page as PDF and uploads
  • +
  • Selection: Captures only selected content as PDF
  • +
  • Context Menu: "Clip Full Page" and "Clip Selection" options
  • +
  • Success: Notification confirms clip was uploaded
-

🔍 Testing Checklist

+

🔍 Testing Checklist (v1.1.0)

+

Installation & Configuration:

    -
  • ✓ Extension icon appears in browser toolbar
  • -
  • ✓ Popup opens when clicking extension icon
  • -
  • ✓ Configuration can be saved (server URL)
  • -
  • ✓ Current URL is displayed in popup
  • -
  • ✓ "Send to DocuElevate" appears in context menu
  • -
  • ✓ Files are successfully sent to DocuElevate
  • -
  • ✓ Success notification appears
  • -
  • ✓ Task ID is displayed in notification
  • -
  • ✓ Error messages are clear and helpful
  • +
  • ☐ Extension icon appears in browser toolbar
  • +
  • ☐ Popup opens when clicking extension icon
  • +
  • ☐ Configuration can be saved (server URL)
  • +
  • ☐ Mode toggle buttons work (URL/Clip)
  • +
+ +

URL Mode:

+
    +
  • ☐ Current URL is displayed in popup
  • +
  • ☐ "Send to DocuElevate" button works
  • +
  • ☐ Context menu "Send URL to DocuElevate" works
  • +
  • ☐ Success notification appears with task ID
  • +
+ +

Clip Mode:

+
    +
  • ☐ "Clip Full Page" button works
  • +
  • ☐ "Clip Selection" button works (after selecting text)
  • +
  • ☐ Context menu "Clip Full Page to DocuElevate" works
  • +
  • ☐ Context menu "Clip Selection to DocuElevate" works
  • +
  • ☐ PDF is generated correctly with styles
  • +
  • ☐ Upload succeeds and task ID is shown
  • +
+ +

Error Handling:

+
    +
  • ☐ Clear error message if server unreachable
  • +
  • ☐ Error message if no text selected (Clip Selection)
  • +
  • ☐ Authentication errors handled properly
@@ -132,11 +197,13 @@
  • Open DevTools (F12) and check the Console for errors
  • Make sure your DocuElevate server is running and accessible
  • If using authentication, verify your session cookie is valid
  • +
  • For clipping: Ensure browser supports chrome.tabs.printToPDF API
  • +
  • Check that /api/files/upload endpoint is accessible