feat(clickTtHttpPageRoutes): add meta-refresh URL rewriting for proxy handling
- Implemented a new function to rewrite meta-refresh URLs in HTML, ensuring redirects after login are routed through the proxy while maintaining session integrity. - Updated the proxy GET and POST endpoints to include the new meta-refresh handling, enhancing the overall functionality of the proxy interactions. - Improved error handling in the new function to ensure robustness in processing HTML content.
This commit is contained in:
@@ -85,6 +85,38 @@ function rewriteLinksInHtml(html, proxyBaseUrl, pageBaseUrl, sid) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Schreibt meta-refresh-URLs um, damit Redirects nach Login über unseren Proxy laufen (Session bleibt erhalten).
|
||||
*/
|
||||
function rewriteMetaRefreshInHtml(html, proxyBaseUrl, pageBaseUrl, sid) {
|
||||
if (!html || !proxyBaseUrl || !pageBaseUrl || !sid) return html;
|
||||
try {
|
||||
const base = new URL(pageBaseUrl);
|
||||
return html.replace(
|
||||
/<meta\s[^>]*(?:http-equiv\s*=\s*["']refresh["'][^>]*content\s*=\s*["']([^"']+)["']|content\s*=\s*["']([^"']+)["'][^>]*http-equiv\s*=\s*["']refresh["'])[^>]*>/gi,
|
||||
(match, content1, content2) => {
|
||||
const content = content1 || content2;
|
||||
if (!content) return match;
|
||||
const urlMatch = content.match(/^\s*\d+\s*;\s*url\s*=\s*(.+)$/i);
|
||||
if (!urlMatch) return match;
|
||||
let targetUrl = urlMatch[1].trim();
|
||||
if ((targetUrl.startsWith("'") && targetUrl.endsWith("'")) || (targetUrl.startsWith('"') && targetUrl.endsWith('"'))) {
|
||||
targetUrl = targetUrl.slice(1, -1);
|
||||
}
|
||||
if (targetUrl.startsWith('/') || !targetUrl.startsWith('http')) {
|
||||
targetUrl = new URL(targetUrl, base.origin + base.pathname).href;
|
||||
}
|
||||
if (!shouldProxyUrl(targetUrl)) return match;
|
||||
const proxyUrl = buildProxyUrl(proxyBaseUrl, targetUrl, sid);
|
||||
const newContent = content.replace(/url\s*=\s*.+$/i, `url=${proxyUrl}`);
|
||||
return match.replace(content, newContent);
|
||||
}
|
||||
);
|
||||
} catch {
|
||||
return html;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Schreibt Formular-Actions um, sodass Submissions über unseren Proxy laufen (Login etc. wird geloggt).
|
||||
*/
|
||||
@@ -198,6 +230,7 @@ router.get('/proxy', async (req, res, next) => {
|
||||
const proxyBase = baseUrl.replace(/\/$/, '') + '/api/clicktt/proxy';
|
||||
html = rewriteLinksInHtml(html, proxyBase, targetUrl, sid);
|
||||
html = rewriteFormActionsInHtml(html, proxyBase, targetUrl, sid);
|
||||
html = rewriteMetaRefreshInHtml(html, proxyBase, targetUrl, sid);
|
||||
|
||||
res.set({
|
||||
'Content-Type': 'text/html; charset=utf-8',
|
||||
@@ -258,8 +291,14 @@ router.post('/proxy', async (req, res, next) => {
|
||||
}
|
||||
(Array.isArray(setCookies) ? setCookies : [setCookies]).forEach(c => res.append('Set-Cookie', c));
|
||||
}
|
||||
const location = responseHeaders.get?.('location') ?? responseHeaders['location'];
|
||||
let location = responseHeaders.get?.('location') ?? responseHeaders['location'];
|
||||
if (location && (result.status >= 301 && result.status <= 308)) {
|
||||
if (location.startsWith('/')) {
|
||||
try {
|
||||
const base = new URL(targetUrl);
|
||||
location = base.origin + location;
|
||||
} catch { /* ignore */ }
|
||||
}
|
||||
const baseUrl = process.env.BACKEND_BASE_URL || process.env.BASE_URL
|
||||
|| `${req.protocol || 'http'}://${req.get('host') || 'localhost:' + (process.env.PORT || 3005)}`;
|
||||
const proxyBase = baseUrl.replace(/\/$/, '') + '/api/clicktt/proxy';
|
||||
@@ -288,6 +327,7 @@ router.post('/proxy', async (req, res, next) => {
|
||||
}
|
||||
responseBody = rewriteLinksInHtml(responseBody, proxyBase, targetUrl, sid);
|
||||
responseBody = rewriteFormActionsInHtml(responseBody, proxyBase, targetUrl, sid);
|
||||
responseBody = rewriteMetaRefreshInHtml(responseBody, proxyBase, targetUrl, sid);
|
||||
}
|
||||
|
||||
res.set({
|
||||
|
||||
@@ -106,15 +106,24 @@ async function fetchWithLogging(options) {
|
||||
const baseDomain = extractBaseDomain(url);
|
||||
const startTime = Date.now();
|
||||
|
||||
let origin;
|
||||
try { origin = new URL(url).origin + '/'; } catch { origin = 'https://httv.click-tt.de/'; }
|
||||
const headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
|
||||
'Accept-Language': 'de,en-US;q=0.7,en;q=0.3',
|
||||
'Referer': origin,
|
||||
'Origin': origin.replace(/\/$/, ''),
|
||||
...customHeaders,
|
||||
};
|
||||
|
||||
try {
|
||||
const fetchOpts = { method, headers, timeout: 30000 };
|
||||
const fetchOpts = {
|
||||
method,
|
||||
headers,
|
||||
timeout: 30000,
|
||||
redirect: method === 'POST' ? 'manual' : 'follow',
|
||||
};
|
||||
if (body && (method === 'POST' || method === 'PUT')) {
|
||||
fetchOpts.body = body;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user