Created
November 5, 2024 13:46
-
-
Save DementedEarplug/da0ef97effcb3e416f8efafb1b2f8b33 to your computer and use it in GitHub Desktop.
Proxy everything
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Adjust proxy server to rewrite URLs | |
// Main proxy route that handles all incoming requests | |
// Takes a URL parameter that specifies which resource to proxy | |
app.get("/proxy/:url", async (req, res) => { | |
// Decode the URL parameter since it comes URL-encoded | |
const url = decodeURIComponent(req.params.url); | |
// Create URL object to help with resolving relative URLs later | |
const baseUrl = new URL(url); | |
try { | |
// Fetch the target URL content as a raw buffer to handle different content types | |
const response = await axios.get(url, { responseType: "arraybuffer" }); | |
const contentType = response.headers["content-type"]; | |
// Forward the original content type header to maintain proper content handling | |
if (contentType) { | |
res.setHeader("Content-Type", contentType); | |
} | |
let html = response.data; | |
// Special handling for HTML content to modify internal resources | |
if (contentType && contentType.includes("text/html")) { | |
// Convert buffer to string for HTML processing | |
html = Buffer.from(html, "binary").toString(); | |
// Parse HTML with Cheerio (jQuery-like API for server-side) | |
const $ = cheerio.load(html); | |
// Process all stylesheet links to proxy them through our server | |
// This ensures CSS files are also fetched through our proxy | |
$('link[rel="stylesheet"]').each((_, element) => { | |
const href = $(element).attr("href"); | |
if (href) { | |
// Convert relative URLs to absolute using the base URL | |
const absoluteUrl = new URL(href, baseUrl.origin); | |
// Rewrite href to go through our proxy | |
$(element).attr( | |
"href", | |
`${req.protocol}://${req.get("host")}/proxy/${encodeURIComponent( | |
absoluteUrl.href | |
)}` | |
); | |
} | |
}); | |
// Process all images to proxy them through our server | |
// Similar to stylesheet processing | |
$("img").each((_, element) => { | |
const src = $(element).attr("src"); | |
if (src) { | |
const absoluteUrl = new URL(src, baseUrl.origin); | |
$(element).attr( | |
"src", | |
`${req.protocol}://${req.get("host")}/proxy/${encodeURIComponent( | |
absoluteUrl.href | |
)}` | |
); | |
} | |
}); | |
// Remove autoplay attributes from video elements | |
// This prevents unwanted automatic video playback | |
$("video[autoplay]").removeAttr("autoplay"); | |
$('video[playsinline]').removeAttr('playsinline'); | |
// Handle iframe elements, particularly for video embeds | |
// Modify their URLs to disable autoplay functionality | |
$("iframe").each((_, element) => { | |
const src = $(element).attr("src"); | |
if (src) { | |
// Special handling for YouTube and Vimeo iframes | |
if (src.includes("youtube.com") || src.includes("vimeo.com")) { | |
const separator = src.includes("?") ? "&" : "?"; | |
const newSrc = `${src}${separator}autoplay=0`; | |
$(element).attr("src", newSrc); | |
} | |
} | |
}); | |
// Handle base tags and links | |
// Remove base tags as they can interfere with our URL rewriting | |
$("base").remove(); | |
// Process all anchor tags to proxy their destinations | |
$("a").each((_, element) => { | |
const href = $(element).attr("href"); | |
if (href) { | |
const absoluteUrl = new URL(href, baseUrl.origin); | |
$(element) | |
.attr( | |
"href", | |
`${req.protocol}://${req.get("host")}/proxy/${encodeURIComponent( | |
absoluteUrl.href | |
)}` | |
) | |
// Force links to open in the same window to maintain proxy context | |
.attr("target", "_self"); | |
} | |
}); | |
// Inject JavaScript to handle client-side behavior | |
// This script ensures proper link handling and video control | |
$("body").append(`<script> | |
// Intercept clicks on proxied links to handle them properly | |
document.addEventListener('click', (evt) => { | |
const target = evt.target; | |
if (target && target.getAttribute('href')?.startsWith('/proxy/')) { | |
evt.preventDefault(); | |
window.location.href = target.getAttribute('href'); | |
} | |
}); | |
// Ensure all videos are paused when the page loads | |
document.addEventListener('DOMContentLoaded', function() { | |
const videos = document.querySelectorAll('video'); | |
videos.forEach(video => { | |
video.pause(); // Ensure videos are paused | |
}); | |
}); | |
</script>`); | |
// Send the modified HTML back to the client | |
res.send($.html()); | |
} else { | |
// For non-HTML content (CSS, images, etc.), send the raw buffer | |
res.send(response.data); | |
} | |
} catch (error) { | |
// Log any errors and send an error response | |
console.error("Error fetching content", error); | |
res.status(500).send("Error fetching content"); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment