diff --git a/.gitignore b/.gitignore index 0ac4c09..a6adf6a 100755 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ snapshot_blob.bin locales/ pnacl/ swiftshader/ +.DS_Store # BASE OMORI STUFF package.json diff --git a/www/modloader/early_loader.js b/www/modloader/early_loader.js index 722236d..ef6281e 100644 --- a/www/modloader/early_loader.js +++ b/www/modloader/early_loader.js @@ -816,8 +816,12 @@ mod = new DirectoryMod(path.join(base, "mods", mod_file)); } else { if (!mod_file.endsWith(".zip")) { - window._logLine("| [ERROR] Skipping, not directory and extension isn't zip"); - errorCount++; + if (mod_file === ".DS_Store") { + window._logLine("| [INFO] Skipping .DS_Store"); + } else { + window._logLine("| [ERROR] Skipping, not directory and extension isn't zip"); + errorCount++; + } continue; } mod = new ZipMod(path.join(base, "mods", mod_file)); diff --git a/www/modloader/vfs_web.js b/www/modloader/vfs_web.js index bfb0f1a..e48be04 100644 --- a/www/modloader/vfs_web.js +++ b/www/modloader/vfs_web.js @@ -1,39 +1,10 @@ function _modLoader_install_debugger_vfs(shadowfs, nativefs) { - if ($modLoader.$nwMajor >= 45) { alert("Versions of NW newer than 0.45.0 are not supported!"); throw new Error();} + if ($modLoader.$nwMajor < 45) { + async function buildResponseBody(data) { + $modLoader.$vfsTrace("WEB REQUEST " + JSON.stringify(data)); + let url = new URL(data.request.url); - async function buildResponseBody(data) { - $modLoader.$vfsTrace("WEB REQUEST " + JSON.stringify(data)); - let url = new URL(data.request.url); - - if ($modLoader.isInTestMode) { if (url.origin === window.location.origin) { - let vfsPath = url.pathname; - try { - let rdata = await _vfs_resolve_file(vfsPath); - let hS = ""; - for (let header in data.responseHeaders) { - hS = `${hS}${header}: ${data.responseHeaders[header]}\n`; - } - - let responseBody = `HTTP/1.1 200 OK\n${hS}\n`; - responseBody = Buffer.concat([Buffer.from(responseBody), rdata]).toString("base64"); - return { - interceptionId: data.interceptionId, - rawResponse: responseBody - }; - } catch(e) { - window._logLine("Error occured when building response body: " + e.stack); - return { - interceptionId: data.interceptionId - } - } - } else { - return { - interceptionId: data.interceptionId - } - } - } else { - if (url.origin === window.location.origin && url.pathname.startsWith("/www/")) { let vfsPath = url.pathname.replace(/^[\/\\]*www[\/\\]*/, ""); try { let rdata = await _vfs_resolve_file(vfsPath); @@ -60,44 +31,28 @@ function _modLoader_install_debugger_vfs(shadowfs, nativefs) { } } } - } - return new Promise(resolve => { - window._logLine("Gathering chrome devtools remote debugging candidates"); - chrome.debugger.getTargets((t) => { - let debugee = {targetId: ""}; - for (let candidate of t) { - if (candidate.url.endsWith("index.html")) { - debugee.targetId = candidate.id; - } - } - - chrome.debugger.detach(debugee, () => { - if(chrome.runtime.lastError) { - console.warn(chrome.runtime.lastError.message); + return new Promise(resolve => { + window._logLine("Gathering chrome devtools remote debugging candidates"); + chrome.debugger.getTargets((t) => { + let debugee = {targetId: ""}; + for (let candidate of t) { + if (candidate.url.endsWith("index.html")) { + debugee.targetId = candidate.id; + } } - chrome.debugger.attach(debugee, "1.2", () => { - window._logLine("[DEVTOOLS] Successfully attached!"); - chrome.debugger.onEvent.addListener(async (debugee, event, data) => { - if (event === "Network.requestIntercepted") { - chrome.debugger.sendCommand(debugee, "Network.continueInterceptedRequest", await buildResponseBody(data)); - } - }); - if (!$modLoader.isInTestMode) { - chrome.debugger.sendCommand( - debugee, - "Network.setRequestInterception", - { - enabled: true, - patterns: [ - { - urlPattern: window.location.origin + "/www/*", - interceptionStage: "HeadersReceived" - } - ] + chrome.debugger.detach(debugee, () => { + if(chrome.runtime.lastError) { + console.warn(chrome.runtime.lastError.message); + } + + chrome.debugger.attach(debugee, "1.2", () => { + window._logLine("[DEVTOOLS] Successfully attached!"); + chrome.debugger.onEvent.addListener(async (debugee, event, data) => { + if (event === "Network.requestIntercepted") { + chrome.debugger.sendCommand(debugee, "Network.continueInterceptedRequest", await buildResponseBody(data)); } - ); - } else { + }); chrome.debugger.sendCommand( debugee, "Network.setRequestInterception", @@ -111,18 +66,166 @@ function _modLoader_install_debugger_vfs(shadowfs, nativefs) { ] } ); - } - setTimeout(resolve, 100); - }); + setTimeout(resolve, 100); + }); - window.__unload_web_vfs = function() { - chrome.debugger.detach(debugee); - }; - window.addEventListener("beforeunload", function(e) { - chrome.debugger.detach(debugee); + window.__unload_web_vfs = function() { + chrome.debugger.detach(debugee); + }; + window.addEventListener("beforeunload", function(e) { + chrome.debugger.detach(debugee); + }); }); + }) + }); + } else { + $modLoader.$log("[VFS_WEB] Starting HTTP server"); + + function readRangeHeader(range, totalLength) { + /* + * Example of the method 'split' with regular expression. + * + * Input: bytes=100-200 + * Output: [null, 100, 200, null] + * + * Input: bytes=-200 + * Output: [null, null, 200, null] + */ + + if (range == null || range.length == 0) + return null; + + var array = range.split(/bytes=([0-9]*)-([0-9]*)/); + var start = parseInt(array[1]); + var end = parseInt(array[2]); + var result = { + Start: isNaN(start) ? 0 : start, + End: isNaN(end) ? (totalLength - 1) : end + }; + + if (!isNaN(start) && isNaN(end)) { + result.Start = start; + result.End = totalLength - 1; + } + + if (isNaN(start) && !isNaN(end)) { + result.Start = totalLength - end; + result.End = totalLength - 1; + } + + return result; + } + + let SERVER_KEY = require('crypto').randomBytes(32).toString('hex'); + let TEST_KEY = require('crypto').randomBytes(32).toString('hex'); + let testKeyChecker; + const path = require('path'); + const base = path.dirname(process.mainModule.filename); + const urlTester = new RegExp(`^/${SERVER_KEY}`); + async function requestListener(req, res) { + try { + if (req.url === `/${SERVER_KEY}/${TEST_KEY}`) { + res.setHeader("Content-Type", "application/json"); + res.writeHead(200); + res.end('{"ready": true}'); + + $modLoader.$vfsTrace(`[VFS_WEB] ${TEST_KEY}`); + $modLoader.$log(`[VFS_WEB] Got Test key. Successfully authenticated client.`); + + return; + } + + if (!urlTester.test(req.url)) { + res.writeHead(400); + res.end('Server key not present!'); + + $modLoader.$vfsTrace(`[VFS_WEB] Unauthorized request to VFS! Path: ${req.url}`); + + return; + } + + let requestPath = req.url.split(new RegExp(`^/${SERVER_KEY}`))[1]; + if (requestPath.startsWith("/www/")) { + requestPath = requestPath.replace(/^\/www/, ""); + } + res.setHeader("Accept-Ranges", "bytes"); + + try { + const data = await _vfs_resolve_file(requestPath); + + let ext = requestPath.match(/\.([^\.]*)$/)[1]; + + let type = Mime.getType(ext); + + res.setHeader("Content-Type", type); + res.setHeader("Access-Control-Allow-Origin", window.location.origin); + let rangeRequest = readRangeHeader(req.headers["range"], data.length); + if (rangeRequest == null) { + res.setHeader("Content-Length", data.length); + res.writeHead(200); + res.end(data); + } else { + res.setHeader("Content-Range", "bytes " + rangeRequest.Start + "-" + rangeRequest.End + "/" + data.length); + res.setHeader("Content-Length", ( + rangeRequest.End - rangeRequest.Start + 1 + )); + res.writeHead(206); + + res.end(data.subarray(rangeRequest.Start, rangeRequest.End + 1)); + } + + $modLoader.$vfsTrace(`[VFS_WEB] Got request ${req.url} (${requestPath})`); + } catch(E) { + console.log(E); + res.writeHead(404); + res.end(''); + } + } catch(E) { + console.log(E); + } + } + + return new Promise(async (resolve, reject) => { + const [server, port] = await new Promise((listening, _) => { + const http = require('http'); + + let server = http.createServer(requestListener); + + server.listen(0, "127.0.0.1", undefined, () => void listening([server, server.address().port])); }); - }) - }); + + $modLoader.$log(`[VFS_WEB] Proxy server listening on Port 127.0.0.1:${port}`); + + function beforeRequestInterceptor(details) { + $modLoader.$vfsTrace("VFS_WEB REQUEST " + JSON.stringify(details)); + let u = new URL(details.url); + if (u.pathname === "/www/modloader/one_loader_sw.js") return null; + return {redirectUrl: `http://127.0.0.1:${port}/${SERVER_KEY}${u.pathname}`} + } + + chrome.webRequest.onBeforeRequest.addListener(beforeRequestInterceptor, { + urls: [ + window.location.origin + "/*" + ] + }, ["blocking"]) + $modLoader.$log(`[VFS_WEB] Registered request listener ${window.location.origin}`); + + window.addEventListener("beforeunload", function(e) { + $modLoader.$log(`[VFS_WEB] Unregistering request listener ${window.location.origin}`); + chrome.webRequest.onBeforeRequest.removeListener(beforeRequestInterceptor); + server.close(); + }); + + testKeyChecker = setInterval(() => { + fetch(`/${TEST_KEY}`).then(a => a.json()).then(a => { + if (a && a.ready === true) { + console.log("test key done"); + resolve(); + clearInterval(testKeyChecker); + } + }).catch(e => {}); + }, 100); + }); + } } \ No newline at end of file diff --git a/www/mods/oneloader/oneloader-update-installer.js b/www/mods/oneloader/oneloader-update-installer.js index 2c71a3e..631383d 100644 --- a/www/mods/oneloader/oneloader-update-installer.js +++ b/www/mods/oneloader/oneloader-update-installer.js @@ -14,10 +14,16 @@ if ($modLoader.config && $modLoader.config._autoUpdater && $modLoader.config._au fs.writeFileSync("_oneloader_update.zip", Buffer.from(bundle)); let zip = new StreamZip.async({ file: "_oneloader_update.zip" }); let entries = await zip.entries(); + let stripWww = false; + try { + fs.accessSync('www'); + } catch (E) { + stripWww = true; + } for (let el in entries) { - try { if (entries[el].isDirectory) { fs.mkdirSync(el); } } catch (e) { } + try { if (entries[el].isDirectory) { fs.mkdirSync(stripWww ? el.replace(/^[\/\\]*www[\/\\]*/, "") : el); } } catch (e) { } if (entries[el].isDirectory) continue; - fs.writeFileSync(el, await zip.entryData(el)); + fs.writeFileSync(stripWww ? el.replace(/^[\/\\]*www[\/\\]*/, "") : el, await zip.entryData(el)); } $modLoader.config._autoUpdater.performUpdate = false; $modLoader.config._autoUpdater.updateBundleURL = undefined; @@ -37,4 +43,4 @@ if ($modLoader.config && $modLoader.config._autoUpdater && $modLoader.config._au console.log(E); window._logLine("Failed to fetch or install update"); } -} \ No newline at end of file +}