diff --git a/zefie_wtvp_minisrv/includes/ServiceDeps/https/zefienetCA.pem b/zefie_wtvp_minisrv/includes/ServiceDeps/https/zefienetCA.pem new file mode 100644 index 00000000..9d1aae8f --- /dev/null +++ b/zefie_wtvp_minisrv/includes/ServiceDeps/https/zefienetCA.pem @@ -0,0 +1,35 @@ +-----BEGIN CERTIFICATE----- +MIIGJzCCBA+gAwIBAgIUTKPx4tUyiX93N/egPKsjfZQNlCUwDQYJKoZIhvcNAQEL +BQAwgaExCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhOZXcgWW9yazEPMA0GA1UEBwwG +SHVkc29uMRcwFQYDVQQKDA5aZWZpZSBOZXR3b3JrczEZMBcGA1UECwwQTG9jYWwg +TmV0d29yayBDQTEaMBgGA1UEAwwRWmVmaWUgTmV0d29ya3MgQ0ExHjAcBgkqhkiG +9w0BCQEWD3plZmllQHplZmllLm5ldDAgFw0yNDEwMTkxNDIzNTdaGA8yMDg0MTAx +OTE0MjM1N1owgaExCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhOZXcgWW9yazEPMA0G +A1UEBwwGSHVkc29uMRcwFQYDVQQKDA5aZWZpZSBOZXR3b3JrczEZMBcGA1UECwwQ +TG9jYWwgTmV0d29yayBDQTEaMBgGA1UEAwwRWmVmaWUgTmV0d29ya3MgQ0ExHjAc +BgkqhkiG9w0BCQEWD3plZmllQHplZmllLm5ldDCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAJxwTr8iA/6kHZ3LL+PUQcAPqk9iRMH5YV4e1Wkq33cefFHN +8s/yqac1is48NJq2G3oEXnQo6e1Bo7Y3NfR4hAHzW7gz/lRxukKkI1XH6QyIVigd +sdRbq13WeDba2YEbJDP1XbbJMFupeZzEhOeG5EMRaqEgl0TE/AjOt2fD1iybA6Dr +z+wMA4LOFbfth0tfOpeioiDAVqkvhp9hl3UF5ThMBplQJ7k3KbX82jwc3Ihl4cla +bT7F+ypKieQx7YRl1JcqZ361TgbIzE/rEG7zK3bH9SJTjtqmphn9/3yZ8ualguqY +VkJz0fdOWPQaqLmR+hQaVlyEfUEEw89MZ/TPHZY8pW79fp7OrM/KEL6mEz8E1zmJ +T6n5+rILA3PM036qn1WEVvmh3Rtv5sINkrg7nNw6vZlDq8lzzu0cae+IqiikkTT+ +oFZ40jFEdd1Cr0m1irU5rLaP/SpDK6uz1T+JWgDSS8vdIARzxMTrNnL0XnEmjVmn +kMab43iQ8UOcOmf/AJAdfzFS6C3SXLsz4aeeMKoEoFlut/8hWD3x6x9CTYUna18U +e5y3Lhe17yASxKCvGHjQ1WvV/FG5MYPosLwTq5Baq57DTrz1rR0oGqjTP5u9ehWg +8+3BbyU3kKEslsNlYsMAzRbqLe430WOBsgcJVMdUKmH7h3FfxmR+jsLrnJCXAgMB +AAGjUzBRMB0GA1UdDgQWBBSWZoNRxAe1AyZeCSu6xOsIIZmiyTAfBgNVHSMEGDAW +gBSWZoNRxAe1AyZeCSu6xOsIIZmiyTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 +DQEBCwUAA4ICAQB7ek8RNQjcf9YlPPrMXsDHomSilDcEcjFZf6614SRjU+5WUgR0 +ABtCBp2X4hZzFq6/Tp/B/Y5Lwcv0jn8EhvZ0eTPQ0hALAvVKUvAh1ZTiQKCNPqTn +xIJmeBKyWSfZUTOGiXoJnyi32wyIiKOLyqNWSFkR8GYIIhqQMTuGnMaXJ+XH2aJH +cNH0iXtl1I/BrVtYPGC5LEEiPVL3tgKPL9EXZik+SkP33IxPFX3DefjfDcsFPEAR +3T4026CTapMNKO3b6oQI8eeh91rLd2gzczdxjjod1W66xiNEdyFkHwxou236ePxV +wUTB6tLYFzT1y2S+ANTbDyJwXnJqm90cO5iwanyofThvStIOSS2WQFuFshpSE7DS +yCyc/z5T2/cM3DTTPJRQvOZHhJQdsS4Za4x/z9y3qi33Ko/L4YKCse49NqGG1BVm +SXajYj62koVmD5ZwvEISRWQaRCRHLAAU3kBZdC4edYmULf4R9ORg2Qe6oAsjoBJg +Sl4rmcM+0/ijviB8lARHNDwsxTUp6uhbe9pPKIH0dFN0G2JIe9tNHX8vpxIL+o9Q +iQRaJWl7eMMfewr7IDfQaajNRjK4XyBsV8NEZn0C/jaq92XNwRjjCDaJul40qbom +bv14SzRZP4arnRlCbfxxGlKfVoMf6rwlxmn5Jf5ArG+wm/+FGzdzcVlDQw== +-----END CERTIFICATE----- diff --git a/zefie_wtvp_minisrv/includes/ServiceVault/wtv-proxy/img/catchall.js b/zefie_wtvp_minisrv/includes/ServiceVault/wtv-proxy/img/catchall.js new file mode 100644 index 00000000..1b17ab9a --- /dev/null +++ b/zefie_wtvp_minisrv/includes/ServiceVault/wtv-proxy/img/catchall.js @@ -0,0 +1,33 @@ +minisrv_service_file = true; +request_is_async = true; + +const proxyUrl = minisrv_config.services['wtv-proxy'].wrp_url; +if (!proxyUrl.endsWith('/')) { + proxyUrl += '/'; +} +// Remove 'wtv-proxy:/' from the start of request_url +let forwardPath = request_headers.request_url.replace(/^wtv-proxy:\//, ''); + +// Build the full URL to forward to +const targetUrl = proxyUrl + forwardPath; + +// Forward the request using http(s) module +const urlObj = new URL(targetUrl); +const lib = urlObj.protocol === 'https:' ? https : http; + +lib.get(targetUrl, (res) => { + let headers = `200 OK\n`; + // Copy content-type if present + if (res.headers['content-type']) { + headers += `Content-Type: ${res.headers['content-type']}\n`; + } + // Optionally copy other headers as needed + + let data = []; + res.on('data', chunk => data.push(chunk)); + res.on('end', () => { + sendToClient(socket, headers, Buffer.concat(data)); + }); +}).on('error', err => { + sendToClient(socket, '200 OK\nContent-Type: text/plain', `Error fetching image: ${err.message}`); +}); \ No newline at end of file diff --git a/zefie_wtvp_minisrv/includes/ServiceVault/wtv-proxy/map/catchall.js b/zefie_wtvp_minisrv/includes/ServiceVault/wtv-proxy/map/catchall.js new file mode 100644 index 00000000..59396b71 --- /dev/null +++ b/zefie_wtvp_minisrv/includes/ServiceVault/wtv-proxy/map/catchall.js @@ -0,0 +1,68 @@ +minisrv_service_file = true; +request_is_async = true; + +const proxyUrl = minisrv_config.services['wtv-proxy'].wrp_url; +if (!proxyUrl.endsWith('/')) { + proxyUrl += '/'; +} +// Remove 'wtv-proxy:/' from the start of request_url +let forwardPath = request_headers.request_url.replace(/^wtv-proxy:\//, ''); + +// Build the full URL to forward to +var targetUrl = proxyUrl + forwardPath; + +// Forward the request using http(s) module +const urlObj = new URL(targetUrl); +const lib = urlObj.protocol === 'https:' ? https : http; + +coords = request_headers.request_url.split("?")[1]; +if (!coords) { + coords = '0,0' +} + +console.log(`Forwarding request to ${targetUrl} with coordinates ${coords}`); +targetUrl += `?${coords}`; // Append coordinates to the target URL + +lib.get(targetUrl, (res) => { + let headers = `200 OK\n`; + // Copy content-type if present + if (res.headers['content-type']) { + headers += `Content-Type: ${res.headers['content-type']}\n`; + } + // Optionally copy other headers as needed + + let data = ''; + res.on('data', chunk => data += chunk); + res.on('end', () => { + if (data.startsWith(' and extract the URLs + const aHrefMatch = data.match(/]+type=["']text["'][^>]+name=["']url["'][^>]+value=["']([^"']+)["']/i); + let pageUrl = ''; + if (urlInputMatch) { + pageUrl = urlInputMatch[1]; + } + var redirectUrl = `wtv-proxy:/proxy?id=${proxy_id}&t=${imgExt}&url=${encodeURIComponent(pageUrl)}`; + sendToClient(socket, {'Status': 302, 'Location': redirectUrl}, ''); + } else { + var idx = data.indexOf('
'); + data = data.substring(0, idx); + var redirectUrl = `wtv-proxy:/proxy?err=${escape(data)}`; + sendToClient(socket, {'Status': 302, 'Location': redirectUrl}, ''); + } + }); +}).on('error', err => { + sendToClient(socket, '200 OK\nContent-Type: text/plain', `Error fetching image: ${err.message}`); +}); \ No newline at end of file diff --git a/zefie_wtvp_minisrv/includes/ServiceVault/wtv-proxy/proxy.js b/zefie_wtvp_minisrv/includes/ServiceVault/wtv-proxy/proxy.js new file mode 100644 index 00000000..b06bb8eb --- /dev/null +++ b/zefie_wtvp_minisrv/includes/ServiceVault/wtv-proxy/proxy.js @@ -0,0 +1,118 @@ +minisrv_service_file = true; +request_is_async = true; + +proxyUrl = minisrv_config.services[service_name].wrp_url; +if (!proxyUrl.endsWith('/')) { + proxyUrl += '/'; +} + +if (!request_headers.query.url) { + headers = `200 OK +Content-Type: text/html`; + data = ` + + + Web Rendering Proxy + + +

Web Rendering Proxy

+

Welcome to the Web Rendering Proxy.
Please provide a valid URL to render.

+
+ + + + + + + +
+ +` + sendToClient(socket, headers, data); +} else { + if (request_headers.query.err) { + finishPage(`

Error

${request_headers.query.err}

`).join('
'); + } else { + const params = new URLSearchParams({ + url: request_headers.query.url, + z: request_headers.query.z || '1.0', + t: request_headers.query.t || 'jpg', + c: request_headers.query.c || '256', + m: request_headers.query.m || 'ismap' + }); + const fullUrl = proxyUrl + '?' + params.toString(); + const urlObj = new URL(fullUrl); + const lib = urlObj.protocol === 'https:' ? https : http; + if (request_headers.query.id) { + finishPage(``); + } else { + function fetch(url) { + return new Promise((resolve, reject) => { + lib.get(url, (res) => { + let data = ''; + res.on('data', chunk => data += chunk); + res.on('end', () => resolve({ text: () => Promise.resolve(data) })); + }).on('error', reject); + }); + } + fetch(fullUrl) + .then(response => response.text()) + .then(text => { process(text); }) + .catch(err => { finishPage(`Error fetching page: ${err.message}`); }); + } + } +} + + +function process(content) { + if (content.startsWith(' and extract the URLs + const aHrefMatch = content.match(/ ``).join('
')); + // You can now use the `links` array as needed + + } else { + var idx = content.indexOf('
'); + content = content.substring(0, idx); + finishPage(content); + } +} + +function finishPage(content) { + headers = `200 OK +Content-Type: text/html`; + data = ` + + + Web Rendering Proxy + + +
+ + + + + + + + +
+ ${content} +
+
+
+Start Over +
+ +`; + sendToClient(socket, headers, data); +} \ No newline at end of file diff --git a/zefie_wtvp_minisrv/includes/ServiceVault/wtv-search/search.js b/zefie_wtvp_minisrv/includes/ServiceVault/wtv-search/search.js new file mode 100644 index 00000000..2735ed6b --- /dev/null +++ b/zefie_wtvp_minisrv/includes/ServiceVault/wtv-search/search.js @@ -0,0 +1,122 @@ +minisrv_service_file = true; +request_is_async = true; + +var searchUrl = minisrv_config.services[service_name].searxng_url; +if (!searchUrl.endsWith('/')) { + searchUrl += '/'; +} +searchUrl += 'search'; + +if (!request_headers.query.q) { + const headers = `200 OK\nContent-Type: text/html`; + const data = ` + + + Web Search Proxy + + +

WebTV Search

+

Please provide a search query.

+
+ + + + + + + +
+ +`; + sendToClient(socket, headers, data); +} else { + const params = new URLSearchParams(); + for (const key in request_headers.query) { + if (request_headers.query.hasOwnProperty(key)) { + params.append(key, request_headers.query[key]); + } + } + params.append('format', 'json'); + const urlObj = new URL(searchUrl); + const lib = urlObj.protocol === 'https:' ? https : http; + var post_data = params.toString(); + const options = { + protocol: urlObj.protocol, + hostname: urlObj.hostname, + port: parseInt(urlObj.port) || (urlObj.protocol === 'https:' ? 443 : 80), + path: urlObj.pathname + (urlObj.search || ''), + method: 'POST', + headers: { + 'User-Agent': request_headers['User-Agent'] || 'Mozilla/4.0 WebTV/2.6 (compatible; MSIE 4.0)', + 'Content-Type': 'application/x-www-form-urlencoded', + 'Content-Length': Buffer.byteLength(post_data), + 'Accept': 'application/json, text/plain, */*', + } + }; + if (urlObj.protocol === 'https:' && urlObj.hostname.includes("lan.zef")) { + options.ca = wtvshared.getServiceDep('https/zefienetCA.pem'); + } + + fetch(lib, options, post_data) + .then(response => response.text()) + .then(text => { process(text); }) + .catch(err => { finishPage(`Error fetching page: ${err.message}`); }); +} + +function fetch(lib, options, post_data) { + return new Promise((resolve, reject) => { + var req = lib.request(options, (res) => { + let data = ''; + res.on('data', chunk => data += chunk); + res.on('end', () => resolve({ text: () => Promise.resolve(data) })); + }).on('error', reject); + req.write(post_data); // 🔁 Send body + req.end(); + }); +} + +function process(data) { + if (data === "Too Many Requests") { + sendToClient(socket, '400 SearXNG reported
"Too Many Requests"

Please check your limiter.toml.\nContent-Type: text/plain', 'SearXNG reported "Too Many Requests", please check your limiter.toml'); + return; + } else { + const results = JSON.parse(data).results || []; + let content = ''; + if (results.length === 0) { + content = '

No results found

'; + } else { + content = '

Search Results

'; + results.forEach(result => { + content += `

${result.title}
${result.content || `` || ''}


`; + }); + } + finishPage(content); + return; + } +} + +function finishPage(content) { + const headers = `200 OK\nContent-Type: text/html`; + const data = ` + + + Web Search Proxy + + +
+ + + + +
+ ${content} + +`; + sendToClient(socket, headers, data); +} \ No newline at end of file diff --git a/zefie_wtvp_minisrv/includes/config.json b/zefie_wtvp_minisrv/includes/config.json index 4d1d51f7..c3a6e1a5 100644 --- a/zefie_wtvp_minisrv/includes/config.json +++ b/zefie_wtvp_minisrv/includes/config.json @@ -392,7 +392,17 @@ "port": 1656, "connections": 3, "flags": "0x00000004" + }, + "wtv-search": { + "disabled": true, + "port": 1695, + "searxng_url": "http://192.168.11.20:9999/" // replace with your own searxng instance }, + "wtv-proxy": { + "disabled": true, + "port": 1696, + "wrp_url": "http://192.168.11.20:8889/" // replace with your own tenox9/wrp + }, "pb_services": { // PC Services for PageBuilder "port": 1697,