From 564291d13e622a1bb60c21739b57279f30d08f28 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 23 Nov 2025 20:41:25 +0000 Subject: [PATCH 1/5] Initial plan From 3764f139e3182a12cd7cf127ba6a311dc3681c5f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 23 Nov 2025 20:49:30 +0000 Subject: [PATCH 2/5] Implement tab/window interception system for Scramjet and Ultraviolet proxies Co-authored-by: sriail <225764385+sriail@users.noreply.github.com> --- public/radius-client.js | 157 ++++++++++++++++++++++++++++++++++++++ public/tab-interceptor.js | 125 ++++++++++++++++++++++++++++++ public/vu/uv.config.js | 3 +- src/pages/index.astro | 33 +++++++- 4 files changed, 315 insertions(+), 3 deletions(-) create mode 100644 public/radius-client.js create mode 100644 public/tab-interceptor.js diff --git a/public/radius-client.js b/public/radius-client.js new file mode 100644 index 0000000..3c7d76d --- /dev/null +++ b/public/radius-client.js @@ -0,0 +1,157 @@ +/** + * Radius Client Script + * + * This script runs in proxied pages to intercept window.open and new tab attempts, + * redirecting them to the parent iframe instead. + * + * This works with both Scramjet and Ultraviolet proxies. + */ + +(function() { + 'use strict'; + + // Check if we're in an iframe + const isInIframe = window.self !== window.top; + + if (!isInIframe) { + // Not in an iframe, no need to intercept + return; + } + + // Store original functions + const originalWindowOpen = window.open; + + /** + * Override window.open to redirect to parent iframe + */ + window.open = function(url, target, features) { + try { + // Notify parent to navigate to the URL + window.parent.postMessage({ + type: 'radius-open-url', + url: url || 'about:blank', + target: target, + features: features + }, '*'); + + // Return a fake window object to satisfy callers + const fakeWindow = { + closed: false, + close: function() { this.closed = true; }, + focus: function() {}, + blur: function() {}, + postMessage: function() {}, + location: { href: url || 'about:blank' }, + document: {}, + opener: window, + parent: window, + top: window, + name: target || '' + }; + + return fakeWindow; + } catch (e) { + console.warn('Radius: Failed to intercept window.open, falling back:', e); + // If postMessage fails, try original (though it may be blocked by sandbox) + return originalWindowOpen.call(this, url, target, features); + } + }; + + // Preserve toString to avoid detection + window.open.toString = function() { + return 'function open() { [native code] }'; + }; + + /** + * Intercept link clicks with target="_blank" or "_new" + */ + document.addEventListener('click', function(event) { + let element = event.target; + + // Traverse up to find an anchor tag + while (element && element.tagName !== 'A') { + element = element.parentElement; + if (!element) return; + } + + // Check if it's a link with target="_blank" or "_new" + if (element.tagName === 'A') { + const target = element.getAttribute('target'); + + if (target === '_blank' || target === '_new') { + // Prevent default new tab behavior + event.preventDefault(); + event.stopPropagation(); + event.stopImmediatePropagation(); + + const href = element.href; + + // Notify parent + try { + window.parent.postMessage({ + type: 'radius-open-url', + url: href, + target: target + }, '*'); + } catch (e) { + console.warn('Radius: Failed to send message to parent:', e); + // Fallback: navigate in current window + window.location.href = href; + } + } + } + }, true); // Use capture to intercept early + + /** + * Intercept form submissions with target="_blank" or "_new" + */ + document.addEventListener('submit', function(event) { + const form = event.target; + + if (form && form.tagName === 'FORM') { + const target = form.getAttribute('target'); + + if (target === '_blank' || target === '_new') { + event.preventDefault(); + event.stopPropagation(); + event.stopImmediatePropagation(); + + const action = form.action; + const method = form.method.toUpperCase() || 'GET'; + + if (method === 'GET') { + // For GET, build URL with form data + const formData = new FormData(form); + const params = new URLSearchParams(formData); + const fullUrl = action + (action.includes('?') ? '&' : '?') + params.toString(); + + try { + window.parent.postMessage({ + type: 'radius-open-url', + url: fullUrl, + target: target + }, '*'); + } catch (e) { + console.warn('Radius: Failed to send form data to parent:', e); + window.location.href = fullUrl; + } + } else { + // For POST and other methods, just navigate to the action URL + // (proper POST handling would require more complex implementation) + try { + window.parent.postMessage({ + type: 'radius-open-url', + url: action, + target: target + }, '*'); + } catch (e) { + console.warn('Radius: Failed to send form action to parent:', e); + window.location.href = action; + } + } + } + } + }, true); + + console.log('Radius client script initialized - new tab/window interception active'); +})(); diff --git a/public/tab-interceptor.js b/public/tab-interceptor.js new file mode 100644 index 0000000..41f6ab3 --- /dev/null +++ b/public/tab-interceptor.js @@ -0,0 +1,125 @@ +/** + * Tab and Window Interceptor for Radius Proxy + * + * This script intercepts attempts to open new tabs or windows in proxied content + * and redirects them to open in the main iframe instead. + * + * Works with both Scramjet and Ultraviolet web proxies. + */ + +(function() { + 'use strict'; + + // Store the original window.open function + const originalWindowOpen = window.open; + + // Get a reference to the parent window (if in iframe) + const isInIframe = window.self !== window.top; + + /** + * Intercept window.open() calls + */ + window.open = function(...args) { + const url = args[0]; + const target = args[1]; + const features = args[2]; + + // If we're in an iframe and can communicate with parent + if (isInIframe && window.parent) { + try { + // Send message to parent to load URL in main iframe + window.parent.postMessage({ + type: 'radius-open-url', + url: url, + target: target, + features: features + }, '*'); + + // Return a fake window object to prevent errors + return { + closed: false, + close: () => {}, + focus: () => {}, + blur: () => {}, + postMessage: () => {} + }; + } catch (e) { + console.warn('Failed to intercept window.open:', e); + // Fallback to original behavior if interception fails + return originalWindowOpen.apply(this, args); + } + } + + // If not in iframe, use original behavior + return originalWindowOpen.apply(this, args); + }; + + /** + * Intercept clicks on links with target="_blank" + */ + document.addEventListener('click', function(event) { + // Find the closest anchor element + let target = event.target; + while (target && target.tagName !== 'A') { + target = target.parentElement; + } + + // If it's a link with target="_blank" or similar + if (target && target.tagName === 'A') { + const linkTarget = target.getAttribute('target'); + + if (linkTarget === '_blank' || linkTarget === '_new') { + event.preventDefault(); + event.stopPropagation(); + + const href = target.href; + + if (isInIframe && window.parent) { + // Send message to parent to load URL in main iframe + window.parent.postMessage({ + type: 'radius-open-url', + url: href, + target: linkTarget + }, '*'); + } else { + // If not in iframe, navigate in current window + window.location.href = href; + } + } + } + }, true); // Use capture phase to intercept before other handlers + + /** + * Intercept form submissions with target="_blank" + */ + document.addEventListener('submit', function(event) { + const form = event.target; + + if (form && form.tagName === 'FORM') { + const formTarget = form.getAttribute('target'); + + if (formTarget === '_blank' || formTarget === '_new') { + event.preventDefault(); + event.stopPropagation(); + + // Build form data + const formData = new FormData(form); + const action = form.action; + const method = form.method || 'GET'; + + if (isInIframe && window.parent) { + // Send message to parent + window.parent.postMessage({ + type: 'radius-form-submit', + url: action, + method: method, + data: Object.fromEntries(formData), + target: formTarget + }, '*'); + } + } + } + }, true); + + console.log('Radius Tab Interceptor loaded'); +})(); diff --git a/public/vu/uv.config.js b/public/vu/uv.config.js index 23dd015..9a5553e 100644 --- a/public/vu/uv.config.js +++ b/public/vu/uv.config.js @@ -25,5 +25,6 @@ self.__uv$config = { client: "/vu/uv.client.js", bundle: "/vu/uv.bundle.js", config: "/vu/uv.config.js", - sw: "/vu/uv.sw.js" + sw: "/vu/uv.sw.js", + inject: "/tab-interceptor.js" // Inject tab interceptor script }; diff --git a/src/pages/index.astro b/src/pages/index.astro index 6d2a5df..c1d4278 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -32,7 +32,7 @@ const link = Astro.url.searchParams.get("redir"); */} -