document.addEventListener('DOMContentLoaded', function () { // Get references to elements const curlButton = document.getElementById('curl'); const curlUrlInput = document.getElementById('curl-url'); const resultsContainer = document.getElementById('curl-results'); // Add click event listener to the button curlButton.addEventListener('click', function () { // Get the URL from the input const url = curlUrlInput.value.trim(); // Validate URL if (!url) { showMessage('Please enter a URL', 'error'); return; } // Update the url var params; if (window.location.search){ params = new URLSearchParams(window.location.search); params.set('url', url); } else { params = new URLSearchParams(); params.append('url', url); } history.pushState(null, null, `?${params.toString()}`); // Show loading state curlButton.disabled = true; curlButton.innerHTML = 'Loading...'; // Clear previous results resultsContainer.innerHTML = ''; showMessage('Fetching content...', 'info'); // Make the request handleCurlRequest(url); }); // Add enter key listener to input curlUrlInput.addEventListener('keyup', function (event) { if (event.key === 'Enter') { curlButton.click(); } }); /** * Handle the curl API request * @param {string} url - The URL to curl */ function handleCurlRequest(url) { // Encode the URL for the API endpoint const encodedUrl = encodeURIComponent(url); const apiEndpoint = `/api/v1/curl/${encodedUrl}`; fetch(apiEndpoint) .then(response => response.json()) .then(data => { // Clear loading message resultsContainer.innerHTML = ''; if (data.success === true) { // Create a result card with iframe const resultCard = document.createElement('div'); resultCard.className = 'card shadow border-0 rounded-lg mb-5'; resultCard.innerHTML = `

Result for ${escapeHtml(url)}

`; resultsContainer.appendChild(resultCard); // Get reference to the iframe and buttons const iframe = document.getElementById('result-iframe'); const viewSourceButton = document.getElementById('view-source'); const newTabButton = document.getElementById('new-tab'); const cleanedHtml = removeScripts(data.result); // Create a blob URL from the cleaned HTML content const blob = new Blob([cleanedHtml], { type: 'text/html' }); const blobUrl = URL.createObjectURL(blob); // Set the iframe src to the blob URL iframe.src = blobUrl; // Add event listener to view source button viewSourceButton.addEventListener('click', function () { // Show source code in a modal or new window const sourceWindow = window.open('', '_blank'); sourceWindow.document.write(` Source for ${escapeHtml(url)} ${escapeHtml(data.result)} `); sourceWindow.document.close(); }); // Add event listener to new tab button newTabButton.addEventListener('click', function () { // Get URL from window.location const proxyurl = `${window.location.protocol}//${window.location.host}/proxy/${url}`; // Open host/proxy/url in new tab window.open(proxyurl, '_blank'); }); // Set up cleanup when iframe is no longer needed window.addEventListener('beforeunload', function () { URL.revokeObjectURL(blobUrl); }); } else { // Show error message showMessage(data.error || 'Failed to get content', 'error'); } }) .catch(error => { showMessage(`Request failed: ${error.message}`, 'error'); }) .finally(() => { // Reset button state curlButton.disabled = false; curlButton.innerHTML = 'HTTP Request'; }); } /** * Remove all script tags and event handlers from HTML content * @param {string} html - The HTML content * @returns {string} - HTML content with scripts removed */ function removeScripts(html) { // Create a DOM parser to work with the HTML const parser = new DOMParser(); const doc = parser.parseFromString(html, 'text/html'); // Remove all script elements const scripts = doc.getElementsByTagName('script'); while (scripts.length > 0) { scripts[0].parentNode.removeChild(scripts[0]); } // Remove inline event handlers from all elements const allElements = doc.getElementsByTagName('*'); for (let i = 0; i < allElements.length; i++) { const element = allElements[i]; const attrs = element.attributes; const attrsToRemove = []; // Collect all event handler attributes (on*) for (let j = 0; j < attrs.length; j++) { if (attrs[j].name.toLowerCase().startsWith('on')) { attrsToRemove.push(attrs[j].name); } } // Remove the collected attributes attrsToRemove.forEach(attr => { element.removeAttribute(attr); }); } // Return the cleaned HTML return doc.documentElement.outerHTML; } /** * Display a message in the results container * @param {string} message - The message to display * @param {string} type - Message type (error, success, info) */ function showMessage(message, type) { // Clear previous content resultsContainer.innerHTML = ''; // Create alert element const alert = document.createElement('div'); alert.className = `alert alert-${getAlertClass(type)} shadow-sm`; alert.innerHTML = message; // Add the alert to the results container resultsContainer.appendChild(alert); } /** * Get Bootstrap alert class based on message type * @param {string} type - Message type * @returns {string} - Bootstrap alert class */ function getAlertClass(type) { switch (type) { case 'error': return 'danger'; case 'success': return 'success'; case 'info': default: return 'info'; } } /** * Escape HTML special characters to prevent XSS * @param {string} text - Text to escape * @returns {string} - Escaped text */ function escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } // Check if params are present if (window.location.search) { const params = new URLSearchParams(window.location.search); const url = params.get('url'); if (url) { // Add url to input curlUrlInput.value = url; // Show loading state curlButton.disabled = true; curlButton.innerHTML = 'Loading...'; handleCurlRequest(url); } } });