From d7e7744f68a6e92c72c27aeb0f8fedd6a02c2e3b Mon Sep 17 00:00:00 2001 From: ReznoRMichael Date: Fri, 19 Feb 2021 00:04:54 +0100 Subject: [PATCH] stage config --- build/app.js | 2 +- src/js/LoadSaveFile.js | 5 ++ webpack.dev.js | 8 ++- webpack.stage.js | 113 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 webpack.stage.js diff --git a/build/app.js b/build/app.js index 238c01d..0f541b7 100644 --- a/build/app.js +++ b/build/app.js @@ -27,7 +27,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _HKCheckCompletion_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./HKCheckCompletion.js */ \"./src/js/HKCheckCompletion.js\");\n/* \r\n Parts of the code thanks to bloodorca https://github.com/bloodorca/hollow (base64.js, functions.js) with slight modifications.\r\n The steps used there for decryption were taken from KayDeeTee https://github.com/KayDeeTee/Hollow-Knight-SaveManager\r\n Without these two people the existence of this tool wouldn't be possible :)\r\n*/\n// ---------------- Constants ----------------- //\n// AES JS for file decryption\nvar aesjs = __webpack_require__(/*! ./aes-js.js */ \"./src/js/aes-js.js\"); // For reading the text area after save decoding\n\n\n\nvar CSHARP_HEADER = [0, 1, 0, 0, 0, 255, 255, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, 6, 1, 0, 0, 0]; // 22 bytes\n\nvar BASE64_ARRAY = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\".split(\"\").map(function (c) {\n return c.charCodeAt(0);\n});\nvar BASE64_DECODE_TABLE = new Map(BASE64_ARRAY.map(function (ord, i) {\n return [ord, i];\n}));\nvar AES_KEY = new TextEncoder().encode('UKu52ePUBwetZ9wNX88o54dnfKRu0T1l'); // encodes a string to Uint8Array (prepare for AES JS)\n\nvar ECB_STREAM_CIPHER = new aesjs.ModeOfOperation.ecb(AES_KEY); // create a new AES stream cipher object using the encoded key\n// ---------------- Variables ----------------- //\n\nvar benchLSFBegin, benchLSFEnd, benchTotal; // ---------------- Functions ----------------- //\n\n/**\r\n * Main input tag file function. Selects the first file, reads it as an Array Buffer, starts the processing of the file when loaded.\r\n * Starts benchmarking.\r\n * @param {FileList} input FileList object containing a list of File objects. The FileList behaves like an array, so you can check its length property to get the number of selected files.\r\n */\n// eslint-disable-next-line no-unused-vars\n\nfunction LoadSaveFile(input, time) {\n var inputFileList = input.files; // console.info(\"Input length: \" + input.files.length)\n // Cease further processing if user canceled the file input dialog\n\n if (inputFileList.length < 1) return false; // start benchmark\n\n benchLSFBegin = time; // Prepares a File object from the first file of the input files for reading as an Array Buffer\n\n var inputFileObject = inputFileList[0]; // Cleans the file list to avoid problems after subsequent use\n // document.getElementById(\"save-area-file\").value = \"\";\n // 1. read file\n // The ArrayBuffer object is used to represent a generic, fixed-length raw binary data buffer.\n // It is an array of bytes, often referred to in other languages as a \"byte array\".\n // new FileReader()\n\n var inputReader = new FileReader(); // readAsArrayBuffer(file)\n\n inputReader.readAsArrayBuffer(inputFileObject); // addEventListener(\"load\", function) - to decode the file when loaded\n\n inputReader.addEventListener(\"load\", ProcessFileObject);\n}\n/**\r\n * Reads the File object as an Array Buffer and does all other operations (decoding, decryption, conversion to string, pasting to text area).\r\n * Launches the HKReadTextArea() function automatically after pasting the string to text area\r\n */\n\n\nfunction ProcessFileObject() {\n var inputArrayBuffer = this.result;\n var decodedString; // 2. Decode file\n\n try {\n // Uint8Array(ArrayBuffer) uint8_t equivalent in C\n inputArrayBuffer = new Uint8Array(inputArrayBuffer); // ArrayBuffer.slice()\n // The slice() method copies up to, but not including, the byte indicated by the end parameter.\n\n inputArrayBuffer.slice(); // remove C# header and LengthPrefixedString header (ArrayBuffer)\n\n inputArrayBuffer = RemoveHeaders(inputArrayBuffer); // base64 Decoding (ArrayBuffer)\n\n inputArrayBuffer = Base64Decode(inputArrayBuffer); // AES decryption (ECB) removes pkcs7 padding (ArrayBuffer)\n\n inputArrayBuffer = AESDecryption(inputArrayBuffer); // Convert ArrayBuffer to string/text TextDecoder().decode(ArrayBuffer)\n\n decodedString = new TextDecoder().decode(inputArrayBuffer); // finish and show benchmark\n\n benchLSFEnd = new Date();\n console.info(\"LoadSaveFile() time (ms) =\", benchLSFEnd - benchLSFBegin); // 4. Analyze the decoded string immediately\n\n try {\n (0,_HKCheckCompletion_js__WEBPACK_IMPORTED_MODULE_0__.HKCheckCompletion)(JSON.parse(decodedString));\n } catch (error) {\n alert(\"This seems like not a valid Hollow Knight save. \".concat(error));\n console.info(\"This seems like not a valid Hollow Knight save. \".concat(error));\n } // 5. Paste decoded string file to text area\n\n\n document.getElementById(\"save-area\").value = \"\";\n document.getElementById(\"save-area\").value = decodedString; // finish total and show benchmark\n\n benchTotal = new Date();\n console.info(\"Total time (ms) =\", benchTotal - benchLSFBegin); // alert(`Decoded String: ${decodedString}`);\n // alert(`Array Buffer: ${inputArrayBuffer}`);\n } catch (error) {\n alert(\"The file cannot be decoded. \".concat(error));\n console.info(\"The file cannot be decoded. \".concat(error));\n }\n}\n/**\r\n * Removes C# header, LengthPrefixedString header and byte 11 at the end of the Uint8 Array Buffer\r\n * @param {Uint8Array} buffer Uint8Array buffer for removing the header from\r\n * @param {Uint8Array} csHeader Uint8Array for the C# header length calculation\r\n * @returns {Uint8Array}\r\n */\n\n\nfunction RemoveHeaders(buffer) {\n var csHeader = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : CSHARP_HEADER;\n // Remove the fixed C# header and byte 11 at the end. \n buffer = buffer.subarray(csHeader.length, buffer.length - 1); // Remove LengthPrefixedString header\n\n var lengthCount = 0;\n\n for (var i = 0; i < 5; i++) {\n lengthCount++;\n\n if ((buffer[i] & 0x80) == 0) {\n break;\n }\n }\n\n return buffer.subarray(lengthCount);\n}\n/**\r\n * Decodes an Array Buffer using a Base64 decode table\r\n * @param {Uint8Array} buffer Uint8Array Buffer to decode\r\n * @returns {Uint8Array}\r\n */\n\n\nfunction Base64Decode(buffer) {\n buffer = new Uint8Array(buffer).slice();\n buffer = buffer.map(function (v) {\n return BASE64_DECODE_TABLE.get(v);\n }); // The indexOf() method returns the first index at which a given element can be found in the array, or -1 if it is not present.\n\n var p = buffer.indexOf(64);\n var end;\n\n if (p != -1) {\n end = p;\n } else {\n end = buffer.length;\n }\n\n buffer = buffer.subarray(0, end);\n var output = new Uint8Array(3 * buffer.length / 4);\n var continuous = Math.floor(buffer.length / 4) * 4;\n\n for (var i = 0; i < continuous; i += 4) {\n var k = 3 * i / 4;\n output[k] = buffer[i] << 2 | buffer[i + 1] >> 4;\n output[k + 1] = (buffer[i + 1] & 0x0F) << 4 | buffer[i + 2] >> 2;\n output[k + 2] = (buffer[i + 2] & 0x03) << 6 | buffer[i + 3];\n }\n\n if (buffer[continuous] != undefined) {\n var _k = 3 * continuous / 4;\n\n output[_k] = buffer[continuous] << 2 | buffer[continuous + 1] >> 4;\n\n if (buffer[continuous + 2] != undefined) {\n output[_k + 1] = (buffer[continuous + 1] & 0x0F) << 4 | buffer[continuous + 2] >> 2;\n }\n }\n\n return output;\n}\n/**\r\n * Decrypt an Uint8Array Buffer using aesjs (ECB) and a predefined AES key + remove pkcs7 padding\r\n * @param {Uint8Array} buffer Uint8Array buffer to decrypt\r\n * @returns {Uint8Array}\r\n */\n\n\nfunction AESDecryption(buffer) {\n var cipherObject = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ECB_STREAM_CIPHER;\n var output = cipherObject.decrypt(buffer);\n return output.subarray(0, -output[output.length - 1]);\n} // Assign actions (functions) to launch when a specific element is used\n\n\ndocument.getElementById(\"save-area-file\").addEventListener(\"change\", function (event) {\n LoadSaveFile(event.target, new Date());\n});\ndocument.getElementById(\"save-area-file\").addEventListener(\"click\", function (mouseEvent) {\n mouseEvent.target.value = \"\";\n});\n\n//# sourceURL=webpack://hollow-knight-completion-check/./src/js/LoadSaveFile.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _HKCheckCompletion_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./HKCheckCompletion.js */ \"./src/js/HKCheckCompletion.js\");\nfunction asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }\n\nfunction _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, \"next\", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, \"throw\", err); } _next(undefined); }); }; }\n\n/* \r\n Parts of the code thanks to bloodorca https://github.com/bloodorca/hollow (base64.js, functions.js) with slight modifications.\r\n The steps used there for decryption were taken from KayDeeTee https://github.com/KayDeeTee/Hollow-Knight-SaveManager\r\n Without these two people the existence of this tool wouldn't be possible :)\r\n*/\n// ---------------- Constants ----------------- //\n// AES JS for file decryption\nvar aesjs = __webpack_require__(/*! ./aes-js.js */ \"./src/js/aes-js.js\"); // For reading the text area after save decoding\n\n\n\nvar CSHARP_HEADER = [0, 1, 0, 0, 0, 255, 255, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, 6, 1, 0, 0, 0]; // 22 bytes\n\nvar BASE64_ARRAY = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\".split(\"\").map(function (c) {\n return c.charCodeAt(0);\n});\nvar BASE64_DECODE_TABLE = new Map(BASE64_ARRAY.map(function (ord, i) {\n return [ord, i];\n}));\nvar AES_KEY = new TextEncoder().encode('UKu52ePUBwetZ9wNX88o54dnfKRu0T1l'); // encodes a string to Uint8Array (prepare for AES JS)\n\nvar ECB_STREAM_CIPHER = new aesjs.ModeOfOperation.ecb(AES_KEY); // create a new AES stream cipher object using the encoded key\n// ---------------- Variables ----------------- //\n\nvar benchLSFBegin, benchLSFEnd, benchTotal; // ---------------- Functions ----------------- //\n\n/**\r\n * Main input tag file function. Selects the first file, reads it as an Array Buffer, starts the processing of the file when loaded.\r\n * Starts benchmarking.\r\n * @param {FileList} input FileList object containing a list of File objects. The FileList behaves like an array, so you can check its length property to get the number of selected files.\r\n */\n// eslint-disable-next-line no-unused-vars\n\nfunction LoadSaveFile(input, time) {\n var inputFileList = input.files; // console.info(\"Input length: \" + input.files.length)\n // Cease further processing if user canceled the file input dialog\n\n if (inputFileList.length < 1) return false; // start benchmark\n\n benchLSFBegin = time; // Prepares a File object from the first file of the input files for reading as an Array Buffer\n\n var inputFileObject = inputFileList[0]; // Cleans the file list to avoid problems after subsequent use\n // document.getElementById(\"save-area-file\").value = \"\";\n // 1. read file\n // The ArrayBuffer object is used to represent a generic, fixed-length raw binary data buffer.\n // It is an array of bytes, often referred to in other languages as a \"byte array\".\n // new FileReader()\n\n var inputReader = new FileReader(); // readAsArrayBuffer(file)\n\n inputReader.readAsArrayBuffer(inputFileObject); // addEventListener(\"load\", function) - to decode the file when loaded\n\n inputReader.addEventListener(\"load\", ProcessFileObject);\n}\n/**\r\n * Reads the File object as an Array Buffer and does all other operations (decoding, decryption, conversion to string, pasting to text area).\r\n * Launches the HKReadTextArea() function automatically after pasting the string to text area\r\n */\n\n\nfunction ProcessFileObject() {\n var inputArrayBuffer = this.result;\n var decodedString; // 2. Decode file\n\n try {\n // Uint8Array(ArrayBuffer) uint8_t equivalent in C\n inputArrayBuffer = new Uint8Array(inputArrayBuffer); // ArrayBuffer.slice()\n // The slice() method copies up to, but not including, the byte indicated by the end parameter.\n\n inputArrayBuffer.slice(); // remove C# header and LengthPrefixedString header (ArrayBuffer)\n\n inputArrayBuffer = RemoveHeaders(inputArrayBuffer); // base64 Decoding (ArrayBuffer)\n\n inputArrayBuffer = Base64Decode(inputArrayBuffer); // AES decryption (ECB) removes pkcs7 padding (ArrayBuffer)\n\n inputArrayBuffer = AESDecryption(inputArrayBuffer); // Convert ArrayBuffer to string/text TextDecoder().decode(ArrayBuffer)\n\n decodedString = new TextDecoder().decode(inputArrayBuffer); // finish and show benchmark\n\n benchLSFEnd = new Date();\n console.info(\"LoadSaveFile() time (ms) =\", benchLSFEnd - benchLSFBegin); // 4. Analyze the decoded string immediately\n\n try {\n (0,_HKCheckCompletion_js__WEBPACK_IMPORTED_MODULE_0__.HKCheckCompletion)(JSON.parse(decodedString));\n } catch (error) {\n alert(\"This seems like not a valid Hollow Knight save. \".concat(error));\n console.info(\"This seems like not a valid Hollow Knight save. \".concat(error));\n } // 5. Paste decoded string file to text area\n\n /* document.getElementById(\"save-area\").value = \"\";\r\n document.getElementById(\"save-area\").value = decodedString; */\n\n\n _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {\n return regeneratorRuntime.wrap(function _callee$(_context) {\n while (1) {\n switch (_context.prev = _context.next) {\n case 0:\n document.getElementById(\"save-area\").value = \"\";\n _context.next = 3;\n return decodedString;\n\n case 3:\n document.getElementById(\"save-area\").value = _context.sent;\n\n case 4:\n case \"end\":\n return _context.stop();\n }\n }\n }, _callee);\n }))(); // finish total and show benchmark\n\n\n benchTotal = new Date();\n console.info(\"Total time (ms) =\", benchTotal - benchLSFBegin); // alert(`Decoded String: ${decodedString}`);\n // alert(`Array Buffer: ${inputArrayBuffer}`);\n } catch (error) {\n alert(\"The file cannot be decoded. \".concat(error));\n console.info(\"The file cannot be decoded. \".concat(error));\n }\n}\n/**\r\n * Removes C# header, LengthPrefixedString header and byte 11 at the end of the Uint8 Array Buffer\r\n * @param {Uint8Array} buffer Uint8Array buffer for removing the header from\r\n * @param {Uint8Array} csHeader Uint8Array for the C# header length calculation\r\n * @returns {Uint8Array}\r\n */\n\n\nfunction RemoveHeaders(buffer) {\n var csHeader = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : CSHARP_HEADER;\n // Remove the fixed C# header and byte 11 at the end. \n buffer = buffer.subarray(csHeader.length, buffer.length - 1); // Remove LengthPrefixedString header\n\n var lengthCount = 0;\n\n for (var i = 0; i < 5; i++) {\n lengthCount++;\n\n if ((buffer[i] & 0x80) == 0) {\n break;\n }\n }\n\n return buffer.subarray(lengthCount);\n}\n/**\r\n * Decodes an Array Buffer using a Base64 decode table\r\n * @param {Uint8Array} buffer Uint8Array Buffer to decode\r\n * @returns {Uint8Array}\r\n */\n\n\nfunction Base64Decode(buffer) {\n buffer = new Uint8Array(buffer).slice();\n buffer = buffer.map(function (v) {\n return BASE64_DECODE_TABLE.get(v);\n }); // The indexOf() method returns the first index at which a given element can be found in the array, or -1 if it is not present.\n\n var p = buffer.indexOf(64);\n var end;\n\n if (p != -1) {\n end = p;\n } else {\n end = buffer.length;\n }\n\n buffer = buffer.subarray(0, end);\n var output = new Uint8Array(3 * buffer.length / 4);\n var continuous = Math.floor(buffer.length / 4) * 4;\n\n for (var i = 0; i < continuous; i += 4) {\n var k = 3 * i / 4;\n output[k] = buffer[i] << 2 | buffer[i + 1] >> 4;\n output[k + 1] = (buffer[i + 1] & 0x0F) << 4 | buffer[i + 2] >> 2;\n output[k + 2] = (buffer[i + 2] & 0x03) << 6 | buffer[i + 3];\n }\n\n if (buffer[continuous] != undefined) {\n var _k = 3 * continuous / 4;\n\n output[_k] = buffer[continuous] << 2 | buffer[continuous + 1] >> 4;\n\n if (buffer[continuous + 2] != undefined) {\n output[_k + 1] = (buffer[continuous + 1] & 0x0F) << 4 | buffer[continuous + 2] >> 2;\n }\n }\n\n return output;\n}\n/**\r\n * Decrypt an Uint8Array Buffer using aesjs (ECB) and a predefined AES key + remove pkcs7 padding\r\n * @param {Uint8Array} buffer Uint8Array buffer to decrypt\r\n * @returns {Uint8Array}\r\n */\n\n\nfunction AESDecryption(buffer) {\n var cipherObject = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ECB_STREAM_CIPHER;\n var output = cipherObject.decrypt(buffer);\n return output.subarray(0, -output[output.length - 1]);\n} // Assign actions (functions) to launch when a specific element is used\n\n\ndocument.getElementById(\"save-area-file\").addEventListener(\"change\", function (event) {\n LoadSaveFile(event.target, new Date());\n});\ndocument.getElementById(\"save-area-file\").addEventListener(\"click\", function (mouseEvent) {\n mouseEvent.target.value = \"\";\n});\n\n//# sourceURL=webpack://hollow-knight-completion-check/./src/js/LoadSaveFile.js?"); /***/ }), diff --git a/src/js/LoadSaveFile.js b/src/js/LoadSaveFile.js index 1e89d94..93b23bc 100644 --- a/src/js/LoadSaveFile.js +++ b/src/js/LoadSaveFile.js @@ -107,6 +107,11 @@ function ProcessFileObject() { document.getElementById("save-area").value = ""; document.getElementById("save-area").value = decodedString; + /* (async () => { + document.getElementById("save-area").value = ""; + document.getElementById("save-area").value = await decodedString; + })(); */ + // finish total and show benchmark benchTotal = new Date(); console.info("Total time (ms) =", benchTotal - benchLSFBegin); diff --git a/webpack.dev.js b/webpack.dev.js index b9ea002..a6e4c33 100644 --- a/webpack.dev.js +++ b/webpack.dev.js @@ -10,6 +10,7 @@ module.exports = { index: './src/js/index.js' }, mode: 'development', + devtool: "source-map", output: { path: `${__dirname}/build`, filename: 'app.js', @@ -43,7 +44,12 @@ module.exports = { use: { loader: 'babel-loader', options: { - presets: ['@babel/preset-env'] + presets: [ + '@babel/preset-env', + { + "useBuiltIns": "entry" + } + ] }, }, }, diff --git a/webpack.stage.js b/webpack.stage.js new file mode 100644 index 0000000..0568b58 --- /dev/null +++ b/webpack.stage.js @@ -0,0 +1,113 @@ +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const HtmlWebpackPartialsPlugin = require('html-webpack-partials-plugin'); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); +const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); +// const TerserPlugin = require('terser-webpack-plugin'); +const { + CleanWebpackPlugin +} = require('clean-webpack-plugin'); + +module.exports = { + entry: { + index: './src/js/index.js', + }, + mode: 'production', + optimization: { + minimize: true, + /* minimizer: [ + new TerserPlugin({ + extractComments: false, + }), + new CssMinimizerPlugin(), + ], */ + }, + output: { + path: `${__dirname}/stage`, + filename: 'app.js', + assetModuleFilename: 'img/[hash][ext][query]', + }, + plugins: [ + new CleanWebpackPlugin(), + new MiniCssExtractPlugin({ + filename: 'main.css' + }), + new HtmlWebpackPlugin({ + template: './src/index.html', + inject: true, + chunks: ['index'], + filename: 'index.html', + favicon: "./src/favicon.png", + minify: { + // Begin HTML Webpack Plugin Default + collapseWhitespace: true, + removeComments: true, + removeRedundantAttributes: true, + removeScriptTypeAttributes: true, + removeStyleLinkTypeAttributes: true, + useShortDoctype: true, + // End HTML Webpack Plugin Default + minifyJS: true, + minifyCSS: true, + }, + }), + new HtmlWebpackPartialsPlugin({ + path: './src/partials/analytics-dev.html', + location: 'head', + priority: 'high', + options: { + ga_property_id: 'UA-136831794-2' + } + }), + new HtmlWebpackPartialsPlugin({ + path: './src/partials/cookiealert.html', + location: 'head', + priority: 'high', + options: { + mainColor: "#59d1da" + } + }), + new CssMinimizerPlugin(), + ], + module: { + rules: [{ + test: /\.js$/, + exclude: /(node_modules|bower_components)/, + use: { + loader: 'babel-loader', + options: { + presets: [ + '@babel/preset-env', + { + "useBuiltIns": "entry" + } + ], + }, + }, + }, + { + test: /\.css$/, + use: [{ + loader: MiniCssExtractPlugin.loader, + options: { + publicPath: "", + }, + }, + // 'style-loader', + 'css-loader', + // 'sass-loader', + ], + }, + { + test: /thumbnail1200x628\.jpg/, + type: 'asset/resource', + generator: { + filename: 'img/[name][ext]' + } + }, + { + test: /\.(svg|jpg|png|ttf|eot|woff|woff2)$/, + type: 'asset', + }, + ], + }, +}; \ No newline at end of file