Skip to content

Latest commit

 

History

History
96 lines (76 loc) · 5.47 KB

File metadata and controls

96 lines (76 loc) · 5.47 KB

Vortex Technical Deep Dive

1. Architecture: The Proxy-Less Browser

Unlike many "browser in browser" solutions that use server-side rendering or proxies, Vortex runs entirely client-side using standard web technologies pushed to their limits via specific Extension APIs.

Core Components

  • Container: A standard React Single Page App (SPA) acting as the "Operating System".
  • Window Manager: React Flow handles the spatial coordinate system (x, y, zoom), occlusion culling (virtualization), and event delegation.
  • Sandboxing: Each "Node" is a standard HTML <iframe>. Use of iframes provides process isolation (handled by the browser's site isolation policy).
  • Bridge: The content-script.js acts as the IPC (Inter-Process Communication) bridge between the "Guest" (iframe) and "Host" (Vortex App).

2. Spawning Mechanics: The Coordinate Algorithm

When a user clicks a link in Node A ($N_a$):

  1. Event Capture: content-script.js uses click event capturing (useCapture: true) to intercept the event before the DOM processes it.
  2. Message Passing: A Chrome Runtime Message is sent:
    { "type": "LINK_CLICK", "url": "https://example.com", "sourceNodeId": "node-123" }
  3. Position Calculation: The Host receives this. It finds $N_a$'s position $(x_a, y_a)$.
    • Naive Algorithm (Current): $P_{new} = (x_a + \text{offset}, y_a)$.
    • Implication: Creates a horizontal chain.
    • Optimization: A force-directed layout or tree-packing algorithm would be safer to avoid overlap, but current naive approach ensures predictable "reading order".

3. The "Unblocking" Hack: Request Modification

This is the most critical and technically "aggressive" part of the stack.

The Problem

Sites send X-Frame-Options: DENY or SAMEORIGIN. Browsers respect this by refusing to render the body of the response in an iframe.

The Solution: declarativeNetRequest

We use the declarativeNetRequest API (Manifest V3) to strip headers at the network layer, before the renderer process sees them.

{
    "id": 1,
    "action": {
        "type": "modifyHeaders",
        "responseHeaders": [
            { "header": "x-frame-options", "operation": "remove" },
            { "header": "content-security-policy", "operation": "remove" }
        ]
    },
    "condition": { "resourceTypes": ["sub_frame"] }
}
  • Result: The browser renderer sees a response with NO security restrictions regarding embedding.
  • Risk: This technically disables Clickjacking protection for these sites within the context of the extension.

4. Limitations & Challenges

A. Auth & Cookies (The "SameSite" Problem)

  • Issue: Many sites (e.g., Google, GitHub) set cookies with SameSite=Lax or Strict.
  • Effect: When embedded in an iframe (even if we force it to load), the browser treats it as a "third-party" context. The cookies are NOT sent.
  • Result: Users may see "Log In" screens even if they are logged in on their main browser tab.
  • Fix: Very hard to fix in MV3.
    • Partial Solution: The extension would need host_permissions to modify Cookie headers to remove SameSite attributes. (Security Risk: High).

B. Memory (RAM Usage)

  • Issue: Each iframe is a full browser context (DOM, JS Heap, Layout Engine). Opening 50 nodes = opening 50 tabs.
  • Scale: Chrome processes are heavy. 50 active iframes can easily consume 4GB+ RAM.
  • Solution: Virtualization / Suspension.
    • Current Imp: We have a "Suspend" button.
    • Ideal Auto-Suspend: Check viewport intersection. If a node is far off-screen, replace the <iframe> with a static screenshot (image). Destroy the iframe to free RAM. Re-hydrate on hover/view.
    • Note: React Flow has onlyRenderVisibleElements, but that just removes the DOM node. Removing the DOM node destroys the iframe state (scroll position, form data). Restoring it reloads the page.

C. Security (XSS & Isolation)

  • Issue: We are embedding arbitrary 3rd party code.
  • Defense:
    • Sandbox Attribute: We use <iframe sandbox="...">.
    • Values: allow-scripts, allow-same-origin, allow-forms.
    • Missing: allow-top-navigation. This prevents the iframe from "breaking out" and redirecting the entire Vortex app to a malicious site.
    • Content Script Isolation: Chrome Extensions run content scripts in an "Isolated World". The page JS cannot touch the content script JS variables, preventing the page from hijacking the extension capabilities.

5. Future Optimizations (How to Solve It)

Solving Memory: The "Frozen" State

Instead of keeping 50 live iframes:

  1. Capture: When a node is inactive, use chrome.tabs.captureVisibleTab (trickier with iframes) or standard HTML2Canvas to take a snapshot.
  2. Freeze: Unmount the iframe, render <img>.
  3. Thaw: On click, remount iframe.
    • Trade-off: You lose scroll position and dynamic state (e.g. video playing).

Solving Auth: The "Partitioned" Cookie

Chrome is moving towards "Partitioned" cookies (CHIPS).

  • Eventually, iframes will have their own "cookie jar" separate from the top-level site. This fixes privacy but doesn't solve "I want to be logged in".
  • Workaround: To truly support seamless auth, Vortex would need to function as a "Tab Manager" that purely visualizes real tabs, rather than embedding them. (i.e. click node -> switch to real tab). But that ruins the "Spatial" experience.