diff --git a/zefie_wtvp_minisrv/app.js b/zefie_wtvp_minisrv/app.js index e7fc0cae..c803f1f7 100644 --- a/zefie_wtvp_minisrv/app.js +++ b/zefie_wtvp_minisrv/app.js @@ -644,11 +644,12 @@ async function processPath(socket, service_vault_file_path, request_headers = ne async function processURL(socket, request_headers, pc_services = false) { var shortURL, headers, data, service_name, original_service_name = ""; - var enable_multi_query = false; + var allow_double_slash, enable_multi_query, use_external_proxy = false; request_headers.query = {}; if (request_headers.request_url) { - if (pc_services) { - original_service_name = request_headers.service_name; // store PC Services service name + service_name = request_headers.service_name; + if (pc_services) { + original_service_name = request_headers.service_name; // store service name service_name = verifyServicePort(request_headers.service_name, socket); // get the actual ServiceVault path delete request_headers.service_name; } @@ -657,7 +658,6 @@ async function processURL(socket, request_headers, pc_services = false) { if (request_headers.request_url.indexOf('?') >= 0) { shortURL = request_headers.request_url.split('?')[0]; - if (minisrv_config.services[service_name]) enable_multi_query = minisrv_config.services[service_name].enable_multi_query || false; var qraw = request_headers.request_url.split('?')[1]; if (qraw.length > 0) { qraw = qraw.split("&"); @@ -779,7 +779,7 @@ async function processURL(socket, request_headers, pc_services = false) { } } - if (ssid_sessions[socket.ssid].get("wtv-my-disk-sucks-sucks-sucks")) { + if (ssid_sessions[socket.ssid].get("wtv-my-disk-sucks-sucks-sucks") && !ssid_sessions[socket.ssid].get("bad_disk_shown")) { if (!ssid_sessions[socket.ssid].baddisk) { // psuedo lockdown, will unlock on the disk warning page, but prevents minisrv access until they read the error ssid_sessions[socket.ssid].lockdown = true; @@ -806,10 +806,13 @@ minisrv-no-mail-count: true`; } else { var service_name = verifyServicePort(shortURL.split(':/')[0], socket); } - var allow_double_slash = false; if (minisrv_config.services[service_name]) { - if (minisrv_config.services[service_name].allow_double_slash) allow_double_slash = true; + allow_double_slash = minisrv_config.services[service_name].allow_double_slash || false; + enable_multi_query = minisrv_config.services[service_name].enable_multi_query || false; + use_external_proxy = minisrv_config.services[service_name].use_external_proxy || false; } + + if ((shortURL.indexOf(':/') >= 0) && (shortURL.indexOf('://') == -1 || (shortURL.indexOf('://') && allow_double_slash))) { var ssid = socket.ssid; if (ssid == null) { @@ -850,7 +853,7 @@ minisrv-no-mail-count: true`; if (minisrv_config.config.debug_flags.show_headers) console.log(" * Incoming headers on socket ID", socket.id, (await wtvshared.decodePostData(wtvshared.filterRequestLog(wtvshared.filterSSID(request_headers))))); socket_sessions[socket.id].request_headers = request_headers; processPath(socket, urlToPath, request_headers, service_name, shared_romcache, pc_services); - } else if ((shortURL.indexOf('http://') >= 0 || shortURL.indexOf('https://') >= 0) && !pc_services) { + } else if (shortURL.indexOf('http://') >= 0 || shortURL.indexOf('https://') >= 0 || (use_external_proxy == true && shortURL.indexOf(service_name + "://") >= 0) && !pc_services) { doHTTPProxy(socket, request_headers); } else if (shortURL.indexOf('file://') >= 0) { shortURL = shortURL.replace("file://",'').replace("romcache", "ROMCache"); @@ -869,6 +872,7 @@ minisrv-no-mail-count: true`; debug('request_headers', request_headers); if (request_headers.request.indexOf("HTTP/1.0") > 0) { // webtv in HTTP/1.0 mode, try to kick it back to WTVP + if (minisrv_config.config.debug_flags.show_headers) console.log(" * Incoming invalid headers on socket ID", socket.id, (await wtvshared.decodePostData(wtvshared.filterRequestLog(wtvshared.filterSSID(request_headers))))); var errpage = wtvshared.doErrorPage(500, null, null, false, true); headers = errpage[0]; data = '' @@ -876,7 +880,8 @@ minisrv-no-mail-count: true`; sendToClient(socket, headers, data); } else { // error reading headers (no request_url provided) - var errpage = wtvshared.doErrorPage(400, null, null, false, true); + if (minisrv_config.config.debug_flags.show_headers) console.log(" * Incoming invalid headers on socket ID", socket.id, (await wtvshared.decodePostData(wtvshared.filterRequestLog(wtvshared.filterSSID(request_headers))))); + var errpage = wtvshared.doErrorPage(400, null, null, false, true); headers = errpage[0]; data = '' socket_sessions[socket.id].close_me = true; @@ -886,14 +891,96 @@ minisrv-no-mail-count: true`; } } +Array.prototype.replace = function(sub, newSub) { + splits = this.split(sub, 2); + return Array.concat(splits[0], newSub, splits[1]) +} + +function handleProxy(socket, request_type, request_headers, res, data) { + console.log(` * Proxy Request ${request_type.toUpperCase()} ${res.statusCode} for ${request_headers.request}`) + // an http response error is not a request error, and will come here under the 'end' event rather than an 'error' event. + switch (res.statusCode) { + case 404: + res.headers.Response = res.statusCode + " The publisher cant find the page requested."; + break; + + case 401: + case 403: + res.headers.Response = res.statusCode + " The publisher of that page has not authorized you to use it."; + break; + + case 500: + res.headers.Response = res.statusCode + " The publisher of that page cant be reached."; + break; + + default: + res.headers.Response = res.statusCode + " " + res.statusMessage; + break; + } + + if (res.headers['Content-yype']) { + res.headers['Content-Type'] = res.headers['Content-Type']; + delete (res.headers['Content-type']) + } + + if (res.headers['content-type']) { + res.headers['Content-Type'] = res.headers['content-type']; + delete (res.headers['content-type']) + } + + if (res.headers['Content-Type'].substr(0, 4) == "text" && request_type != "http" && request_type != "https") { + var data_t = data.toString().replaceAll("http://", request_type + "://").replaceAll("https://", request_type + "://"); + data = [Buffer.from(data_t)] + } + + + // header pass-through whitelist, case insensitive comparsion to server, however, you should + // specify the header case as you intend for the client + var headers = stripHeaders(res.headers, [ + 'Connection', + 'Server', + 'Date', + 'Content-Type', + 'Cookie', + 'Location', + 'Accept-Ranges', + 'Last-Modified' + ]); + headers["wtv-http-proxy"] = true; + headers["wtv-trusted"] = false; + + // if Connection: close header, set our internal variable to close the socket + if (headers['Connection']) { + if (headers['Connection'].toLowerCase().indexOf('close') !== -1) { + headers["wtv-connection-close"] = true; + } + } + + // if a wtv-explaination is defined for an error code (except 200), define the header here to + // show the 'Explain' button on the client error ShowAlert + if (minisrv_config.services['http']['wtv-explanation']) { + if (minisrv_config.services['http']['wtv-explanation'][res.statusCode]) { + headers['wtv-explanation-url'] = minisrv_config.services['http']['wtv-explanation'][res.statusCode]; + } + } + var data_hex = Buffer.concat(data).toString('hex'); + if (data_hex.substring(0, 8) == "0d0a0d0a") data_hex = data_hex.substring(8); + if (data_hex.substring(0, 4) == "0a0a") data_hex = data_hex.substring(4); + sendToClient(socket, headers, Buffer.from(data_hex, 'hex')); +} + async function doHTTPProxy(socket, request_headers) { - var request_type = (request_headers.request_url.substring(0, 5) == "https") ? "https" : "http"; + // detect protocol name + var idx = request_headers.request_url.indexOf('/') - 1; + + var request_type = request_headers.request_url.substring(0, idx); if (minisrv_config.config.debug_flags.show_headers) console.log(request_type.toUpperCase() + " Proxy: Client Request Headers on socket ID", socket.id, (await wtvshared.decodePostData(wtvshared.filterRequestLog(wtvshared.filterSSID(request_headers))))); switch (request_type) { case "https": var proxy_agent = https; break; case "http": + case "proto": var proxy_agent = http; break; } @@ -911,7 +998,6 @@ async function doHTTPProxy(socket, request_headers) { } for (var i = 0; i < 3; i++) request_url_split.shift(); request_data.path = "/" + request_url_split.join('/'); - if (request_data.method && request_data.host && request_data.path) { var options = { @@ -949,91 +1035,61 @@ async function doHTTPProxy(socket, request_headers) { options.port = minisrv_config.services[request_type].external_proxy_port; options.path = request_headers.request.split(' ')[1]; options.headers.Host = request_data.host + ":" + request_data.port; + options.headers.Connection = 'close'; + options.insecureHTTPParser = true; + if (minisrv_config.services[request_type].replace_protocol) { + options.path = options.path.replace(request_type, minisrv_config.services[request_type].replace_protocol); + } + } + if (minisrv_config.services[request_type].external_proxy_is_http1) { + options.insecureHTTPParser = true; + options.headers.Connection = 'close' } } const req = proxy_agent.request(options, function (res) { var data = []; + var data_handled = false; res.on('data', d => { data.push(d); }) res.on('error', function (err) { - console.log(" * Unhandled Proxy Request Error:", err); + // hack for Protoweb ECONNRESET + if (minisrv_config.services[request_type].external_proxy_is_http1 && data.length > 0 && !data_handled) { + handleProxy(socket, request_type, request_headers, res, data); + data_handled = true + } else { + console.log(" * Unhandled Proxy Request Error:", err); + } }); res.on('end', function () { - var data_hex = Buffer.concat(data).toString('hex'); - - console.log(` * Proxy Request ${request_type.toUpperCase()} ${res.statusCode} for ${request_headers.request}`) - // an http response error is not a request error, and will come here under the 'end' event rather than an 'error' event. - switch (res.statusCode) { - case 404: - res.headers.Response = res.statusCode + " The publisher cant find the page requested."; - break; - - case 401: - case 403: - res.headers.Response = res.statusCode + " The publisher of that page has not authorized you to use it."; - break; - - case 500: - res.headers.Response = res.statusCode + " The publisher of that page cant be reached."; - break; - - default: - res.headers.Response = res.statusCode + " " + res.statusMessage; - break; + // Hack for when old http proxies behave correctly + if (!minisrv_config.services[request_type].external_proxy_is_http1 || data.length > 0 && !data_handled) { + handleProxy(socket, request_type, request_headers, res, data); + data_handled = true; } - - // header pass-through whitelist, case insensitive comparsion to server, however, you should - // specify the header case as you intend for the client - var headers = stripHeaders(res.headers, [ - 'Connection', - 'Server', - 'Date', - 'Content-Type', - 'Cookie', - 'Location', - 'Accept-Ranges', - 'Last-Modified' - ]); - headers["wtv-http-proxy"] = true; - headers["wtv-trusted"] = false; - - // if Connection: close header, set our internal variable to close the socket - if (headers['Connection']) { - if (headers['Connection'].toLowerCase().indexOf('close') !== -1) { - headers["wtv-connection-close"] = true; - } - } - - // if a wtv-explaination is defined for an error code (except 200), define the header here to - // show the 'Explain' button on the client error ShowAlert - if (minisrv_config.services['http']['wtv-explanation']) { - if (minisrv_config.services['http']['wtv-explanation'][res.statusCode]) { - headers['wtv-explanation-url'] = minisrv_config.services['http']['wtv-explanation'][res.statusCode]; - } - } - - if (data_hex.substring(0, 8) == "0d0a0d0a") data_hex = data_hex.substring(8); - if (data_hex.substring(0, 4) == "0a0a") data_hex = data_hex.substring(4); - sendToClient(socket, headers, Buffer.from(data_hex, 'hex')); }); }).on('error', function (err) { - // severe errors, such as unable to connect. + // severe errors, such as unable to connect. var errpage, headers, data = null; if (err.code == "ENOTFOUND" || err.message.indexOf("HostUnreachable") > 0) { errpage = wtvshared.doErrorPage(400, `The publisher ${request_data.host} is unknown.`); + } else { + if (minisrv_config.services[request_type].external_proxy_is_http1 && !data_handled) { + handleProxy(socket, request_type, request_headers, res, data); + data_handled = true; + } else { + console.log(" * Unhandled Proxy Request Error:", err); + errpage = wtvshared.doErrorPage(400); + headers = errpage[0]; + data = errpage[1]; + sendToClient(socket, headers, data); + } } - else { - console.log(" * Unhandled Proxy Request Error:", err); - errpage = wtvshared.doErrorPage(400); - } - headers = errpage[0]; - data = errpage[1]; - sendToClient(socket, headers, data); - });; + + }); if (request_headers.post_data) { req.write(Buffer.from(request_headers.post_data.toString(CryptoJS.enc.Hex), 'hex'), function () { req.end(); @@ -1473,12 +1529,13 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq if (headers["wtv-client-serial-number"] != null && socket.ssid == null) { socket.ssid = wtvshared.makeSafeSSID(headers["wtv-client-serial-number"]); if (minisrv_config.config.require_valid_ssid) { - if (!wtvshared.checkSSID(headers["wtv-client-serial-number"])) { + if (!wtvshared.checkSSID(socket.ssid)) { if (socket.ssid.substring(0, 5) != "1SEGA" && socket.ssid.substring(0, 8) != "MSTVSIMU") { // reject invalid SSIDs, but let Dreamcast and MSTV Sim through for now until we figure out their checksumming method. var errpage = wtvshared.doErrorPage(400, "minisrv ran into a technical problem. Reason: Your SSID is not valid."); headers = errpage[0]; data = errpage[1]; + socket.close_me = true; sendToClient(socket, headers, data); return; } @@ -1573,7 +1630,7 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq } if (socket_sessions[socket.id].secure != true) { // first time so reroll sessions - if (minisrv_config.config.debug_flags.debug) console.log(" # [ SECURE ON BLOCK (" + socket.id + ") ]"); + //if (minisrv_config.config.debug_flags.debug) console.log(" # [ SECURE ON BLOCK (" + socket.id + ") ]"); socket_sessions[socket.id].secure = true; } if (!headers.request_url) { @@ -1823,17 +1880,27 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq } } } - } else { - cleanupSocket(socket); } } catch (e) { - cleanupSocket(socket); + var errpage = wtvshared.doErrorPage(400); + headers = errpage[0]; + data = errpage[1]; + socket.close_me = true; + sendToClient(socket, headers, data); } } else { - cleanupSocket(socket); + var errpage = wtvshared.doErrorPage(400); + headers = errpage[0]; + data = errpage[1]; + socket.close_me = true; + sendToClient(socket, headers, data); } } else { - cleanupSocket(socket); + var errpage = wtvshared.doErrorPage(400); + headers = errpage[0]; + data = errpage[1]; + socket.close_me = true; + sendToClient(socket, headers, data); } } diff --git a/zefie_wtvp_minisrv/includes/ServiceVault/wtv-disk/content/Music/headspace/Instruments/Compressed1.2/Patches.hsb b/zefie_wtvp_minisrv/includes/ServiceVault/wtv-disk/content/Music/headspace/Instruments/Compressed1.2/Patches.hsb new file mode 100644 index 00000000..e6742f4b Binary files /dev/null and b/zefie_wtvp_minisrv/includes/ServiceVault/wtv-disk/content/Music/headspace/Instruments/Compressed1.2/Patches.hsb differ diff --git a/zefie_wtvp_minisrv/includes/ServiceVault/wtv-head-waiter/ValidateLogin.js b/zefie_wtvp_minisrv/includes/ServiceVault/wtv-head-waiter/ValidateLogin.js index f5eef53c..a3f706ca 100644 --- a/zefie_wtvp_minisrv/includes/ServiceVault/wtv-head-waiter/ValidateLogin.js +++ b/zefie_wtvp_minisrv/includes/ServiceVault/wtv-head-waiter/ValidateLogin.js @@ -69,7 +69,7 @@ minisrv-no-mail-count: true `; } } else { - if (session_data.baddisk === true) { + if (session_data.baddisk === true && !ssid_sessions[socket.ssid].get("bad_disk_shown")) { gourl = "wtv-head-waiter:/bad-disk?" } else if (session_data.getNumberOfUserAccounts() > 1 && user_id === 0 && (!session_data.isUserLoggedIn() || request_headers.query.initial_login || request_headers.query.relogin) ) { diff --git a/zefie_wtvp_minisrv/includes/ServiceVault/wtv-head-waiter/bad-disk.js b/zefie_wtvp_minisrv/includes/ServiceVault/wtv-head-waiter/bad-disk.js index f56f6a8c..bb7bc00c 100644 --- a/zefie_wtvp_minisrv/includes/ServiceVault/wtv-head-waiter/bad-disk.js +++ b/zefie_wtvp_minisrv/includes/ServiceVault/wtv-head-waiter/bad-disk.js @@ -2,8 +2,7 @@ var minisrv_service_file = true; // remove restrictions once this page is shown, since the user will be 'trapped' anyway session_data.disableLockdown(); -session_data.delete("wtv-my-disk-sucks-sucks-sucks"); -session_data.baddisk = false; +ssid_sessions[socket.ssid].set("bad_disk_shown", true) headers = `200 OK Content-type: text/html`; @@ -77,15 +76,17 @@ switch (wtvshared.getManufacturer(session_data.ssid, true)) { } data += ` -
| - |