From 9de31396923d3e3be4e7b6c202d61b8718eea56f Mon Sep 17 00:00:00 2001 From: kupppo Date: Fri, 1 Jul 2022 16:38:53 +0100 Subject: [PATCH 1/8] initial esbuild + packaging setup --- .gitignore | 1 + web/install.sh | 1 + web/js/customizer.ts | 11 +++ web/js/helpers/hasFileReader.ts | 5 ++ web/js/rom.ts | 10 +++ web/package.json | 12 +++ web/static/customizer.js | 23 ++++++ web/views/customizer.html | 6 ++ web/yarn.lock | 129 ++++++++++++++++++++++++++++++++ 9 files changed, 198 insertions(+) create mode 100644 web/js/customizer.ts create mode 100644 web/js/helpers/hasFileReader.ts create mode 100644 web/js/rom.ts create mode 100644 web/package.json create mode 100644 web/static/customizer.js create mode 100644 web/yarn.lock diff --git a/.gitignore b/.gitignore index c2956c75f..083718ccb 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ *.py[oc] +web/node_modules diff --git a/web/install.sh b/web/install.sh index a1b21ca5b..679cee5cb 100755 --- a/web/install.sh +++ b/web/install.sh @@ -77,6 +77,7 @@ find ~/web2py/applications/solver/static -xtype l -exec rm -f {} \; [ -L ~/web2py/applications/solver/static/js/localforage.nopromises.min.js ] || ln -s ~/RandomMetroidSolver/web/static/localforage.nopromises.min.js ~/web2py/applications/solver/static/js/localforage.nopromises.min.js [ -L ~/web2py/applications/solver/static/js/spc_snes.js ] || ln -s ~/RandomMetroidSolver/web/static/spc_js/spc_snes.js ~/web2py/applications/solver/static/js/spc_snes.js [ -L ~/web2py/applications/solver/static/js/spc_snes.js.mem ] || ln -s ~/RandomMetroidSolver/web/static/spc_js/spc_snes.js.mem ~/web2py/applications/solver/static/js/spc_snes.js.mem +[ -L ~/web2py/applications/solver/static/js/customizer.js ] || ln -s ~/RandomMetroidSolver/web/static/customizer.js ~/web2py/applications/solver/static/js/customizer.js mkdir -p ~/web2py/applications/solver/static/images/common/ [ -L ~/web2py/applications/solver/static/images/common/area_map_20200112.png ] || ln -s ~/RandomMetroidSolver/web/static/area_map.png ~/web2py/applications/solver/static/images/common/area_map_20200112.png diff --git a/web/js/customizer.ts b/web/js/customizer.ts new file mode 100644 index 000000000..46bcd28b0 --- /dev/null +++ b/web/js/customizer.ts @@ -0,0 +1,11 @@ +import handleROM from './rom' + +async function main() { + console.log('sup its main') + handleROM() +} + +main() + .catch((err) => { + console.error(err) + }) diff --git a/web/js/helpers/hasFileReader.ts b/web/js/helpers/hasFileReader.ts new file mode 100644 index 000000000..d15181e73 --- /dev/null +++ b/web/js/helpers/hasFileReader.ts @@ -0,0 +1,5 @@ +const hasFileReader = () => ( + window.File && window.FileList && window.FileReader +) + +export default hasFileReader diff --git a/web/js/rom.ts b/web/js/rom.ts new file mode 100644 index 000000000..c7fe52a9d --- /dev/null +++ b/web/js/rom.ts @@ -0,0 +1,10 @@ +import hasFileReader from './helpers/hasFileReader' + +export default function handleROMSelect() { + if (!hasFileReader()) { + alert('This website requires the HTML5 File API, please upgrade your browser to a newer version.') + return + } + + console.log('handle selecting the ROM') +} diff --git a/web/package.json b/web/package.json new file mode 100644 index 000000000..b0b72b4e3 --- /dev/null +++ b/web/package.json @@ -0,0 +1,12 @@ +{ + "name": "varia-web", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "scripts": { + "build": "esbuild js/customizer.ts --bundle --outdir=static" + }, + "devDependencies": { + "esbuild": "^0.14.48" + } +} diff --git a/web/static/customizer.js b/web/static/customizer.js new file mode 100644 index 000000000..035547f74 --- /dev/null +++ b/web/static/customizer.js @@ -0,0 +1,23 @@ +(() => { + // js/helpers/hasFileReader.ts + var hasFileReader = () => window.File && window.FileList && window.FileReader; + var hasFileReader_default = hasFileReader; + + // js/rom.ts + function handleROMSelect() { + if (!hasFileReader_default()) { + alert("This website requires the HTML5 File API, please upgrade your browser to a newer version."); + return; + } + console.log("handle selecting the ROM"); + } + + // js/customizer.ts + async function main() { + console.log("sup its main"); + handleROMSelect(); + } + main().catch((err) => { + console.error(err); + }); +})(); diff --git a/web/views/customizer.html b/web/views/customizer.html index b952c0afd..9abb1a7c1 100644 --- a/web/views/customizer.html +++ b/web/views/customizer.html @@ -5,6 +5,7 @@ + @@ -864,6 +865,11 @@ } romSize = file.size; + + if(romSize == 3146240) { + console.log("headered ROM detected, removing first 512 bytes of the header"); + } + if( romSize > 4*1024*1024 ) { document.getElementById("uploadFile").value = ""; alert("wrong rom file size: "+romSize.toString()); diff --git a/web/yarn.lock b/web/yarn.lock new file mode 100644 index 000000000..c057d3aa4 --- /dev/null +++ b/web/yarn.lock @@ -0,0 +1,129 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +esbuild-android-64@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.48.tgz#7e6394a0e517f738641385aaf553c7e4fb6d1ae3" + integrity sha512-3aMjboap/kqwCUpGWIjsk20TtxVoKck8/4Tu19rubh7t5Ra0Yrpg30Mt1QXXlipOazrEceGeWurXKeFJgkPOUg== + +esbuild-android-arm64@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.48.tgz#6877566be0f82dd5a43030c0007d06ece7f7c02f" + integrity sha512-vptI3K0wGALiDq+EvRuZotZrJqkYkN5282iAfcffjI5lmGG9G1ta/CIVauhY42MBXwEgDJkweiDcDMRLzBZC4g== + +esbuild-darwin-64@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.48.tgz#ea3caddb707d88f844b1aa1dea5ff3b0a71ef1fd" + integrity sha512-gGQZa4+hab2Va/Zww94YbshLuWteyKGD3+EsVon8EWTWhnHFRm5N9NbALNbwi/7hQ/hM1Zm4FuHg+k6BLsl5UA== + +esbuild-darwin-arm64@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.48.tgz#4e5eaab54df66cc319b76a2ac0e8af4e6f0d9c2f" + integrity sha512-bFjnNEXjhZT+IZ8RvRGNJthLWNHV5JkCtuOFOnjvo5pC0sk2/QVk0Qc06g2PV3J0TcU6kaPC3RN9yy9w2PSLEA== + +esbuild-freebsd-64@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.48.tgz#47b5abc7426eae66861490ffbb380acc67af5b15" + integrity sha512-1NOlwRxmOsnPcWOGTB10JKAkYSb2nue0oM1AfHWunW/mv3wERfJmnYlGzL3UAOIUXZqW8GeA2mv+QGwq7DToqA== + +esbuild-freebsd-arm64@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.48.tgz#e8c54c8637cd44feed967ea12338b0a4da3a7b11" + integrity sha512-gXqKdO8wabVcYtluAbikDH2jhXp+Klq5oCD5qbVyUG6tFiGhrC9oczKq3vIrrtwcxDQqK6+HDYK8Zrd4bCA9Gw== + +esbuild-linux-32@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.48.tgz#229cf3246de2b7937c3ac13fac622d4d7a1344c5" + integrity sha512-ghGyDfS289z/LReZQUuuKq9KlTiTspxL8SITBFQFAFRA/IkIvDpnZnCAKTCjGXAmUqroMQfKJXMxyjJA69c/nQ== + +esbuild-linux-64@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.48.tgz#7c0e7226c02c42aacc5656c36977493dc1e96c4f" + integrity sha512-vni3p/gppLMVZLghI7oMqbOZdGmLbbKR23XFARKnszCIBpEMEDxOMNIKPmMItQrmH/iJrL1z8Jt2nynY0bE1ug== + +esbuild-linux-arm64@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.48.tgz#0af1eda474b5c6cc0cace8235b74d0cb8fcf57a7" + integrity sha512-3CFsOlpoxlKPRevEHq8aAntgYGYkE1N9yRYAcPyng/p4Wyx0tPR5SBYsxLKcgPB9mR8chHEhtWYz6EZ+H199Zw== + +esbuild-linux-arm@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.48.tgz#de4d1fa6b77cdcd00e2bb43dd0801e4680f0ab52" + integrity sha512-+VfSV7Akh1XUiDNXgqgY1cUP1i2vjI+BmlyXRfVz5AfV3jbpde8JTs5Q9sYgaoq5cWfuKfoZB/QkGOI+QcL1Tw== + +esbuild-linux-mips64le@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.48.tgz#822c1778495f7868e990d4da47ad7281df28fd15" + integrity sha512-cs0uOiRlPp6ymknDnjajCgvDMSsLw5mST2UXh+ZIrXTj2Ifyf2aAP3Iw4DiqgnyYLV2O/v/yWBJx+WfmKEpNLA== + +esbuild-linux-ppc64le@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.48.tgz#55de0a9ec4a48fedfe82a63e083164d001709447" + integrity sha512-+2F0vJMkuI0Wie/wcSPDCqXvSFEELH7Jubxb7mpWrA/4NpT+/byjxDz0gG6R1WJoeDefcrMfpBx4GFNN1JQorQ== + +esbuild-linux-riscv64@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.48.tgz#cd2b7381880b2f4b21a5a598fb673492120f18a5" + integrity sha512-BmaK/GfEE+5F2/QDrIXteFGKnVHGxlnK9MjdVKMTfvtmudjY3k2t8NtlY4qemKSizc+QwyombGWTBDc76rxePA== + +esbuild-linux-s390x@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.48.tgz#4b319eca2a5c64637fc7397ffbd9671719cdb6bf" + integrity sha512-tndw/0B9jiCL+KWKo0TSMaUm5UWBLsfCKVdbfMlb3d5LeV9WbijZ8Ordia8SAYv38VSJWOEt6eDCdOx8LqkC4g== + +esbuild-netbsd-64@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.48.tgz#c27cde8b5cb55dcc227943a18ab078fb98d0adbf" + integrity sha512-V9hgXfwf/T901Lr1wkOfoevtyNkrxmMcRHyticybBUHookznipMOHoF41Al68QBsqBxnITCEpjjd4yAos7z9Tw== + +esbuild-openbsd-64@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.48.tgz#af5ab2d1cb41f09064bba9465fc8bf1309150df1" + integrity sha512-+IHf4JcbnnBl4T52egorXMatil/za0awqzg2Vy6FBgPcBpisDWT2sVz/tNdrK9kAqj+GZG/jZdrOkj7wsrNTKA== + +esbuild-sunos-64@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.48.tgz#db3ae20526055cf6fd5c4582676233814603ac54" + integrity sha512-77m8bsr5wOpOWbGi9KSqDphcq6dFeJyun8TA+12JW/GAjyfTwVtOnN8DOt6DSPUfEV+ltVMNqtXUeTeMAxl5KA== + +esbuild-windows-32@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.48.tgz#021ffceb0a3f83078262870da88a912293c57475" + integrity sha512-EPgRuTPP8vK9maxpTGDe5lSoIBHGKO/AuxDncg5O3NkrPeLNdvvK8oywB0zGaAZXxYWfNNSHskvvDgmfVTguhg== + +esbuild-windows-64@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.48.tgz#a4d3407b580f9faac51f61eec095fa985fb3fee4" + integrity sha512-YmpXjdT1q0b8ictSdGwH3M8VCoqPpK1/UArze3X199w6u8hUx3V8BhAi1WjbsfDYRBanVVtduAhh2sirImtAvA== + +esbuild-windows-arm64@0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.48.tgz#762c0562127d8b09bfb70a3c816460742dd82880" + integrity sha512-HHaOMCsCXp0rz5BT2crTka6MPWVno121NKApsGs/OIW5QC0ggC69YMGs1aJct9/9FSUF4A1xNE/cLvgB5svR4g== + +esbuild@^0.14.48: + version "0.14.48" + resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.14.48.tgz#da5d8d25cd2d940c45ea0cfecdca727f7aee2b85" + integrity sha512-w6N1Yn5MtqK2U1/WZTX9ZqUVb8IOLZkZ5AdHkT6x3cHDMVsYWC7WPdiLmx19w3i4Rwzy5LqsEMtVihG3e4rFzA== + optionalDependencies: + esbuild-android-64 "0.14.48" + esbuild-android-arm64 "0.14.48" + esbuild-darwin-64 "0.14.48" + esbuild-darwin-arm64 "0.14.48" + esbuild-freebsd-64 "0.14.48" + esbuild-freebsd-arm64 "0.14.48" + esbuild-linux-32 "0.14.48" + esbuild-linux-64 "0.14.48" + esbuild-linux-arm "0.14.48" + esbuild-linux-arm64 "0.14.48" + esbuild-linux-mips64le "0.14.48" + esbuild-linux-ppc64le "0.14.48" + esbuild-linux-riscv64 "0.14.48" + esbuild-linux-s390x "0.14.48" + esbuild-netbsd-64 "0.14.48" + esbuild-openbsd-64 "0.14.48" + esbuild-sunos-64 "0.14.48" + esbuild-windows-32 "0.14.48" + esbuild-windows-64 "0.14.48" + esbuild-windows-arm64 "0.14.48" From b449c044363bfd0a49f7610b7795b554b655ba00 Mon Sep 17 00:00:00 2001 From: kupppo Date: Mon, 4 Jul 2022 12:25:38 +0100 Subject: [PATCH 2/8] settings + file extension enforcement --- web/js/constants.ts | 2 + web/js/customizer.ts | 15 +-- web/js/helpers/settings.ts | 23 +++++ web/js/rom.ts | 45 +++++++- web/static/customizer.js | 60 +++++++++-- web/views/customizer.html | 207 ++++++++++++++++++++----------------- 6 files changed, 234 insertions(+), 118 deletions(-) create mode 100644 web/js/constants.ts create mode 100644 web/js/helpers/settings.ts diff --git a/web/js/constants.ts b/web/js/constants.ts new file mode 100644 index 000000000..3af7ee026 --- /dev/null +++ b/web/js/constants.ts @@ -0,0 +1,2 @@ +export const VANILLA_ROM_SIZE = 0x300000 +export const HEADERED_ROM_SIZE = 3146240 \ No newline at end of file diff --git a/web/js/customizer.ts b/web/js/customizer.ts index 46bcd28b0..9d069b4ce 100644 --- a/web/js/customizer.ts +++ b/web/js/customizer.ts @@ -1,11 +1,12 @@ -import handleROM from './rom' +import vanillaRom from './rom' async function main() { - console.log('sup its main') - handleROM() + new vanillaRom() } -main() - .catch((err) => { - console.error(err) - }) +document.addEventListener('DOMContentLoaded', () => { + main() + .catch((err) => { + console.error(err) + }) +}) diff --git a/web/js/helpers/settings.ts b/web/js/helpers/settings.ts new file mode 100644 index 000000000..4ece8e0a6 --- /dev/null +++ b/web/js/helpers/settings.ts @@ -0,0 +1,23 @@ +let SETTINGS + +declare global { + interface Window { + VARIA_SETTINGS: VariaSettings + } +} + +export type VariaSettings = { + permalink?: boolean +} + +const DEFAULTS: VariaSettings = { + permalink: false +}; + +(() => { + SETTINGS = Object.assign({}, DEFAULTS, window.VARIA_SETTINGS) +})() + +const getSettings = () => SETTINGS + +export default getSettings diff --git a/web/js/rom.ts b/web/js/rom.ts index c7fe52a9d..8cadcb304 100644 --- a/web/js/rom.ts +++ b/web/js/rom.ts @@ -1,10 +1,45 @@ import hasFileReader from './helpers/hasFileReader' +import Settings from './helpers/settings' -export default function handleROMSelect() { - if (!hasFileReader()) { - alert('This website requires the HTML5 File API, please upgrade your browser to a newer version.') - return +const VALID_EXTENSIONS = ['sfc', 'smc'] + +class VanillaROM { + el: HTMLElement | null + + constructor() { + if (!hasFileReader()) { + alert('This website requires the HTML5 File API, please upgrade your browser to a newer version.') + return + } + const settings = Settings() + const selector = settings.permalink ? 'vanillaUploadFile' : 'uploadFile' + this.el = document.getElementById(selector) + const readFile = this.readFile.bind(this) + this.el?.addEventListener('change', (evt: Event) => { + const file = (evt.target).files?.[0] + if (file) { + readFile(file) + } + }) + } + + getFileExtension(name) { + const lastDot = name.lastIndexOf('.') + return name.substring(lastDot + 1).toLowerCase() } - console.log('handle selecting the ROM') + validateFileExtension(extension) { + if (VALID_EXTENSIONS.includes(extension)) { + return true + } + throw Error(`Unsupported file extension: ${extension}`) + } + + readFile(file: File) { + const extension = this.getFileExtension(file.name) + this.validateFileExtension(extension) + console.log('valid file extension') + } } + +export default VanillaROM diff --git a/web/static/customizer.js b/web/static/customizer.js index 035547f74..a331da444 100644 --- a/web/static/customizer.js +++ b/web/static/customizer.js @@ -3,21 +3,61 @@ var hasFileReader = () => window.File && window.FileList && window.FileReader; var hasFileReader_default = hasFileReader; + // js/helpers/settings.ts + var SETTINGS; + var DEFAULTS = { + permalink: false + }; + (() => { + SETTINGS = Object.assign({}, DEFAULTS, window.VARIA_SETTINGS); + })(); + var getSettings = () => SETTINGS; + var settings_default = getSettings; + // js/rom.ts - function handleROMSelect() { - if (!hasFileReader_default()) { - alert("This website requires the HTML5 File API, please upgrade your browser to a newer version."); - return; + var VALID_EXTENSIONS = ["sfc", "smc"]; + var VanillaROM = class { + constructor() { + if (!hasFileReader_default()) { + alert("This website requires the HTML5 File API, please upgrade your browser to a newer version."); + return; + } + const settings = settings_default(); + const selector = settings.permalink ? "vanillaUploadFile" : "uploadFile"; + this.el = document.getElementById(selector); + const readFile = this.readFile.bind(this); + this.el?.addEventListener("change", (evt) => { + const file = evt.target.files?.[0]; + if (file) { + readFile(file); + } + }); } - console.log("handle selecting the ROM"); - } + getFileExtension(name) { + const lastDot = name.lastIndexOf("."); + return name.substring(lastDot + 1).toLowerCase(); + } + validateFileExtension(extension) { + if (VALID_EXTENSIONS.includes(extension)) { + return true; + } + throw Error(`Unsupported file extension: ${extension}`); + } + readFile(file) { + const extension = this.getFileExtension(file.name); + this.validateFileExtension(extension); + console.log("valid file extension"); + } + }; + var rom_default = VanillaROM; // js/customizer.ts async function main() { - console.log("sup its main"); - handleROMSelect(); + new rom_default(); } - main().catch((err) => { - console.error(err); + document.addEventListener("DOMContentLoaded", () => { + main().catch((err) => { + console.error(err); + }); }); })(); diff --git a/web/views/customizer.html b/web/views/customizer.html index 9abb1a7c1..6943c38c3 100644 --- a/web/views/customizer.html +++ b/web/views/customizer.html @@ -4,8 +4,23 @@ + +{{ if seedInfo is not None: }} + +{{ else:}} + +{{ pass }} + - + @@ -841,99 +856,99 @@ }} window.onload = function(){ //Check File API support - if(window.File && window.FileList && window.FileReader) { - if(permalink == true) { - var inputName = "vanillaUploadFile"; - } else { - var inputName = "uploadFile"; - } - var filesInput = document.getElementById(inputName); - filesInput.addEventListener("change", function(event){ - var files = event.target.files; //It returns a FileList object - var file = files[0]; - - var reader = new FileReader(); - reader.onload = function(e) { - // check sfc or smc extention - var re = /(?:\.([^.]+))?$/; - var ext = re.exec(file.name)[1]; - console.log("ext: "+ext) - if( ! (ext === "sfc" || ext === "smc" || ext === "SFC" || ext === "SMC") ) { - document.getElementById("uploadFile").value = ""; - alert("wrong extension: "+ext); - return false; - } - - romSize = file.size; - - if(romSize == 3146240) { - console.log("headered ROM detected, removing first 512 bytes of the header"); - } - - if( romSize > 4*1024*1024 ) { - document.getElementById("uploadFile").value = ""; - alert("wrong rom file size: "+romSize.toString()); - return false; - } - - var crc32 = new Crc32(); - crc32.update(e.target.result); - var digest = crc32.digest(); - console.log("crc32: "+digest); - var isVanilla = digest == "d63ed5f8"; - - if(permalink == true) { - if(! isVanilla) { - alert("Non vanilla ROM detected"); - document.getElementById(inputName).value = ""; - return false; - } - - // store file in localforage - localforage.setItem('vanillaROM', e.target.result, function(err, value) { - if(err != null) { - console.log("error detected with local storage: "+err); - clearLocalStorage(); - } else { - console.log("vanilla ROM stored in local storage"); - vanillaROMBytes = new Uint8Array(value); - displayROMInput(false); - } - }); - - } else { - // detect race mode patch - isRace = false; - var bytes = new Uint8Array(e.target.result); - for(var addr=0x1C0200; addr<0x1C0210; addr++) { - if(bytes[addr] != 0xff) { - isRace = true; - console.log("race mode detected"); - break; - } - } - - // detect varia default patches - isVARIA = false; - if(bytes[0x175ca] == 0x60 && bytes[0x19E1] == 0xEA && bytes[0xF27] == 0x20) { - isVARIA = true; - } - - // detect beam doors patch from seed to customize - beamDoorsPatch = bytes[0x226e5] == 0x0D; - isArea = bytes[0x788A0] == 0x2b; - isBoss = bytes[0x1a2b6] != 0x00; - - greyOutPatches(isRace, isVARIA, isVanilla); - } - } - - reader.readAsArrayBuffer(file) - - }, false); - } else { - alert("This website requires the HTML5 File API, please upgrade your browser to a newer version."); - } + // if(window.File && window.FileList && window.FileReader) { + // if(permalink == true) { + // var inputName = "vanillaUploadFile"; + // } else { + // var inputName = "uploadFile"; + // } + // var filesInput = document.getElementById(inputName); + // filesInput.addEventListener("change", function(event){ + // var files = event.target.files; //It returns a FileList object + // var file = files[0]; + + // var reader = new FileReader(); + // reader.onload = function(e) { + // // check sfc or smc extention + // var re = /(?:\.([^.]+))?$/; + // var ext = re.exec(file.name)[1]; + // console.log("ext: "+ext) + // if( ! (ext === "sfc" || ext === "smc" || ext === "SFC" || ext === "SMC") ) { + // document.getElementById("uploadFile").value = ""; + // alert("wrong extension: "+ext); + // return false; + // } + + // romSize = file.size; + + // if(romSize == 3146240) { + // console.log("headered ROM detected, removing first 512 bytes of the header"); + // } + + // if( romSize > 4*1024*1024 ) { + // document.getElementById("uploadFile").value = ""; + // alert("wrong rom file size: "+romSize.toString()); + // return false; + // } + + // var crc32 = new Crc32(); + // crc32.update(e.target.result); + // var digest = crc32.digest(); + // console.log("crc32: "+digest); + // var isVanilla = digest == "d63ed5f8"; + + // if(permalink == true) { + // if(! isVanilla) { + // alert("Non vanilla ROM detected"); + // document.getElementById(inputName).value = ""; + // return false; + // } + + // // store file in localforage + // localforage.setItem('vanillaROM', e.target.result, function(err, value) { + // if(err != null) { + // console.log("error detected with local storage: "+err); + // clearLocalStorage(); + // } else { + // console.log("vanilla ROM stored in local storage"); + // vanillaROMBytes = new Uint8Array(value); + // displayROMInput(false); + // } + // }); + + // } else { + // // detect race mode patch + // isRace = false; + // var bytes = new Uint8Array(e.target.result); + // for(var addr=0x1C0200; addr<0x1C0210; addr++) { + // if(bytes[addr] != 0xff) { + // isRace = true; + // console.log("race mode detected"); + // break; + // } + // } + + // // detect varia default patches + // isVARIA = false; + // if(bytes[0x175ca] == 0x60 && bytes[0x19E1] == 0xEA && bytes[0xF27] == 0x20) { + // isVARIA = true; + // } + + // // detect beam doors patch from seed to customize + // beamDoorsPatch = bytes[0x226e5] == 0x0D; + // isArea = bytes[0x788A0] == 0x2b; + // isBoss = bytes[0x1a2b6] != 0x00; + + // greyOutPatches(isRace, isVARIA, isVanilla); + // } + // } + + // reader.readAsArrayBuffer(file) + + // }, false); + // } else { + // alert("This website requires the HTML5 File API, please upgrade your browser to a newer version."); + // } var inputs = document.getElementsByTagName("input"); @@ -1614,7 +1629,7 @@ ROM: - {{=INPUT(_type="file", _name="uploadFile", _id="uploadFile", _class="full")}} + {{=INPUT(_type="file", _accept=".smc,.sfc", _name="uploadFile", _id="uploadFile", _class="full")}} @@ -1993,7 +2008,7 @@

Download seed {{=seedInfo["filename"]}}

Vanilla ROM:
- {{=INPUT(_type="file", _name="vanillaUploadFile", _id="vanillaUploadFile", _class="full")}} + {{=INPUT(_type="file", _accept=".smc,.sfc", _name="vanillaUploadFile", _id="vanillaUploadFile", _class="full")}}
Vanilla ROM already loaded From 1381b415e60e0c4bdc5aebaba50f48954ae3225f Mon Sep 17 00:00:00 2001 From: kupppo Date: Mon, 4 Jul 2022 12:30:33 +0100 Subject: [PATCH 3/8] cleaner file extension --- web/js/rom.ts | 10 +++------- web/static/customizer.js | 9 +++------ 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/web/js/rom.ts b/web/js/rom.ts index 8cadcb304..73a8cb201 100644 --- a/web/js/rom.ts +++ b/web/js/rom.ts @@ -23,12 +23,9 @@ class VanillaROM { }) } - getFileExtension(name) { + validateFileExtension(name: string) { const lastDot = name.lastIndexOf('.') - return name.substring(lastDot + 1).toLowerCase() - } - - validateFileExtension(extension) { + const extension = name.substring(lastDot + 1).toLowerCase() if (VALID_EXTENSIONS.includes(extension)) { return true } @@ -36,8 +33,7 @@ class VanillaROM { } readFile(file: File) { - const extension = this.getFileExtension(file.name) - this.validateFileExtension(extension) + this.validateFileExtension(file.name) console.log('valid file extension') } } diff --git a/web/static/customizer.js b/web/static/customizer.js index a331da444..3dc60ce83 100644 --- a/web/static/customizer.js +++ b/web/static/customizer.js @@ -33,19 +33,16 @@ } }); } - getFileExtension(name) { + validateFileExtension(name) { const lastDot = name.lastIndexOf("."); - return name.substring(lastDot + 1).toLowerCase(); - } - validateFileExtension(extension) { + const extension = name.substring(lastDot + 1).toLowerCase(); if (VALID_EXTENSIONS.includes(extension)) { return true; } throw Error(`Unsupported file extension: ${extension}`); } readFile(file) { - const extension = this.getFileExtension(file.name); - this.validateFileExtension(extension); + this.validateFileExtension(file.name); console.log("valid file extension"); } }; From 234b29f88f869960aa7ce071ab76b88bd5168618 Mon Sep 17 00:00:00 2001 From: kupppo Date: Mon, 4 Jul 2022 13:21:37 +0100 Subject: [PATCH 4/8] automatically remove header if at headered filesize --- web/js/constants.ts | 3 +- web/js/customizer.ts | 2 +- web/js/helpers/crc32.ts | 89 +++++++++++ web/js/rom.ts | 41 ++++- web/package.json | 3 +- web/static/customizer.js | 318 ++++++++++++++++++++++++++++++++++++++- 6 files changed, 444 insertions(+), 12 deletions(-) create mode 100644 web/js/helpers/crc32.ts diff --git a/web/js/constants.ts b/web/js/constants.ts index 3af7ee026..677a81387 100644 --- a/web/js/constants.ts +++ b/web/js/constants.ts @@ -1,2 +1,3 @@ export const VANILLA_ROM_SIZE = 0x300000 -export const HEADERED_ROM_SIZE = 3146240 \ No newline at end of file +export const HEADERED_ROM_SIZE = 3146240 +export const VANILLA_CRC32 = 'd63ed5f8' diff --git a/web/js/customizer.ts b/web/js/customizer.ts index 9d069b4ce..9d1d35875 100644 --- a/web/js/customizer.ts +++ b/web/js/customizer.ts @@ -4,7 +4,7 @@ async function main() { new vanillaRom() } -document.addEventListener('DOMContentLoaded', () => { +window.addEventListener('load', () => { main() .catch((err) => { console.error(err) diff --git a/web/js/helpers/crc32.ts b/web/js/helpers/crc32.ts new file mode 100644 index 000000000..b1ed56838 --- /dev/null +++ b/web/js/helpers/crc32.ts @@ -0,0 +1,89 @@ +"use strict" +class Crc32 { + constructor() { + this.crc = -1 >>> 0; + } + update(data) { + var dataView = new Uint8Array(data, 0); + var len = dataView.length; + for (var i = 0; i < len; i++) { + this.crc = (this.crc >>> 8) ^ Crc32.lookup[(this.crc ^ dataView[i]) & 0xFF]; + } + }; + digest(s) { + s = s || 16; + var buffer = new ArrayBuffer(4); + var dv = new DataView(buffer); + dv.setUint32(0, ~this.crc >>> 0, false); + return dv.getUint32(0).toString(s); + }; +} + +Crc32.lookup = [ + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, + 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, + 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, + 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, + 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, + 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, + 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, + 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, + 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, + 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, + 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, + 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, + 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, + 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, + 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, + 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, + 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, + 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, + 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, + 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, + 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, + 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +]; + +export default Crc32 diff --git a/web/js/rom.ts b/web/js/rom.ts index 73a8cb201..78f46a6b9 100644 --- a/web/js/rom.ts +++ b/web/js/rom.ts @@ -1,5 +1,7 @@ import hasFileReader from './helpers/hasFileReader' import Settings from './helpers/settings' +import Crc32 from './helpers/crc32' +import { VANILLA_CRC32 } from './constants' const VALID_EXTENSIONS = ['sfc', 'smc'] @@ -14,15 +16,37 @@ class VanillaROM { const settings = Settings() const selector = settings.permalink ? 'vanillaUploadFile' : 'uploadFile' this.el = document.getElementById(selector) - const readFile = this.readFile.bind(this) + const useFile = this.useFile.bind(this) this.el?.addEventListener('change', (evt: Event) => { const file = (evt.target).files?.[0] if (file) { - readFile(file) + useFile(file) } }) } + validateChecksum(content) { + const fileSize = content.byteLength + if (fileSize === 3146240) { + console.log('potential headered ROM') + content = content.slice(512) + } else if (fileSize > 4*1024*1024) { + throw Error(`Filesize is too big: ${content.size.toString()}`) + } else { + console.log('correct size') + } + + const crc32 = new Crc32() + crc32.update(content) + const checksum = crc32.digest() + + if (checksum !== VANILLA_CRC32) { + throw Error('Non-Vanilla ROM detected') + } + + return true + } + validateFileExtension(name: string) { const lastDot = name.lastIndexOf('.') const extension = name.substring(lastDot + 1).toLowerCase() @@ -32,9 +56,18 @@ class VanillaROM { throw Error(`Unsupported file extension: ${extension}`) } - readFile(file: File) { + readFile(evt) { + const content = evt.target.result + this.validateChecksum(content) + } + + useFile(file: File) { this.validateFileExtension(file.name) - console.log('valid file extension') + + const reader = new FileReader() + const onLoad = this.readFile.bind(this) + reader.addEventListener('load', onLoad) + reader.readAsArrayBuffer(file) } } diff --git a/web/package.json b/web/package.json index b0b72b4e3..cc10c4034 100644 --- a/web/package.json +++ b/web/package.json @@ -8,5 +8,6 @@ }, "devDependencies": { "esbuild": "^0.14.48" - } + }, + "dependencies": {} } diff --git a/web/static/customizer.js b/web/static/customizer.js index 3dc60ce83..0b93a435d 100644 --- a/web/static/customizer.js +++ b/web/static/customizer.js @@ -14,6 +14,289 @@ var getSettings = () => SETTINGS; var settings_default = getSettings; + // js/helpers/crc32.ts + var Crc32 = class { + constructor() { + this.crc = -1 >>> 0; + } + update(data) { + var dataView = new Uint8Array(data, 0); + var len = dataView.length; + for (var i = 0; i < len; i++) { + this.crc = this.crc >>> 8 ^ Crc32.lookup[(this.crc ^ dataView[i]) & 255]; + } + } + digest(s) { + s = s || 16; + var buffer = new ArrayBuffer(4); + var dv = new DataView(buffer); + dv.setUint32(0, ~this.crc >>> 0, false); + return dv.getUint32(0).toString(s); + } + }; + Crc32.lookup = [ + 0, + 1996959894, + 3993919788, + 2567524794, + 124634137, + 1886057615, + 3915621685, + 2657392035, + 249268274, + 2044508324, + 3772115230, + 2547177864, + 162941995, + 2125561021, + 3887607047, + 2428444049, + 498536548, + 1789927666, + 4089016648, + 2227061214, + 450548861, + 1843258603, + 4107580753, + 2211677639, + 325883990, + 1684777152, + 4251122042, + 2321926636, + 335633487, + 1661365465, + 4195302755, + 2366115317, + 997073096, + 1281953886, + 3579855332, + 2724688242, + 1006888145, + 1258607687, + 3524101629, + 2768942443, + 901097722, + 1119000684, + 3686517206, + 2898065728, + 853044451, + 1172266101, + 3705015759, + 2882616665, + 651767980, + 1373503546, + 3369554304, + 3218104598, + 565507253, + 1454621731, + 3485111705, + 3099436303, + 671266974, + 1594198024, + 3322730930, + 2970347812, + 795835527, + 1483230225, + 3244367275, + 3060149565, + 1994146192, + 31158534, + 2563907772, + 4023717930, + 1907459465, + 112637215, + 2680153253, + 3904427059, + 2013776290, + 251722036, + 2517215374, + 3775830040, + 2137656763, + 141376813, + 2439277719, + 3865271297, + 1802195444, + 476864866, + 2238001368, + 4066508878, + 1812370925, + 453092731, + 2181625025, + 4111451223, + 1706088902, + 314042704, + 2344532202, + 4240017532, + 1658658271, + 366619977, + 2362670323, + 4224994405, + 1303535960, + 984961486, + 2747007092, + 3569037538, + 1256170817, + 1037604311, + 2765210733, + 3554079995, + 1131014506, + 879679996, + 2909243462, + 3663771856, + 1141124467, + 855842277, + 2852801631, + 3708648649, + 1342533948, + 654459306, + 3188396048, + 3373015174, + 1466479909, + 544179635, + 3110523913, + 3462522015, + 1591671054, + 702138776, + 2966460450, + 3352799412, + 1504918807, + 783551873, + 3082640443, + 3233442989, + 3988292384, + 2596254646, + 62317068, + 1957810842, + 3939845945, + 2647816111, + 81470997, + 1943803523, + 3814918930, + 2489596804, + 225274430, + 2053790376, + 3826175755, + 2466906013, + 167816743, + 2097651377, + 4027552580, + 2265490386, + 503444072, + 1762050814, + 4150417245, + 2154129355, + 426522225, + 1852507879, + 4275313526, + 2312317920, + 282753626, + 1742555852, + 4189708143, + 2394877945, + 397917763, + 1622183637, + 3604390888, + 2714866558, + 953729732, + 1340076626, + 3518719985, + 2797360999, + 1068828381, + 1219638859, + 3624741850, + 2936675148, + 906185462, + 1090812512, + 3747672003, + 2825379669, + 829329135, + 1181335161, + 3412177804, + 3160834842, + 628085408, + 1382605366, + 3423369109, + 3138078467, + 570562233, + 1426400815, + 3317316542, + 2998733608, + 733239954, + 1555261956, + 3268935591, + 3050360625, + 752459403, + 1541320221, + 2607071920, + 3965973030, + 1969922972, + 40735498, + 2617837225, + 3943577151, + 1913087877, + 83908371, + 2512341634, + 3803740692, + 2075208622, + 213261112, + 2463272603, + 3855990285, + 2094854071, + 198958881, + 2262029012, + 4057260610, + 1759359992, + 534414190, + 2176718541, + 4139329115, + 1873836001, + 414664567, + 2282248934, + 4279200368, + 1711684554, + 285281116, + 2405801727, + 4167216745, + 1634467795, + 376229701, + 2685067896, + 3608007406, + 1308918612, + 956543938, + 2808555105, + 3495958263, + 1231636301, + 1047427035, + 2932959818, + 3654703836, + 1088359270, + 936918e3, + 2847714899, + 3736837829, + 1202900863, + 817233897, + 3183342108, + 3401237130, + 1404277552, + 615818150, + 3134207493, + 3453421203, + 1423857449, + 601450431, + 3009837614, + 3294710456, + 1567103746, + 711928724, + 3020668471, + 3272380065, + 1510334235, + 755167117 + ]; + var crc32_default = Crc32; + + // js/constants.ts + var VANILLA_CRC32 = "d63ed5f8"; + // js/rom.ts var VALID_EXTENSIONS = ["sfc", "smc"]; var VanillaROM = class { @@ -25,14 +308,32 @@ const settings = settings_default(); const selector = settings.permalink ? "vanillaUploadFile" : "uploadFile"; this.el = document.getElementById(selector); - const readFile = this.readFile.bind(this); + const useFile = this.useFile.bind(this); this.el?.addEventListener("change", (evt) => { const file = evt.target.files?.[0]; if (file) { - readFile(file); + useFile(file); } }); } + validateChecksum(content) { + const fileSize = content.byteLength; + if (fileSize === 3146240) { + console.log("potential headered ROM"); + content = content.slice(512); + } else if (fileSize > 4 * 1024 * 1024) { + throw Error(`Filesize is too big: ${content.size.toString()}`); + } else { + console.log("correct size"); + } + const crc32 = new crc32_default(); + crc32.update(content); + const checksum = crc32.digest(); + if (checksum !== VANILLA_CRC32) { + throw Error("Non-Vanilla ROM detected"); + } + return true; + } validateFileExtension(name) { const lastDot = name.lastIndexOf("."); const extension = name.substring(lastDot + 1).toLowerCase(); @@ -41,9 +342,16 @@ } throw Error(`Unsupported file extension: ${extension}`); } - readFile(file) { + readFile(evt) { + const content = evt.target.result; + this.validateChecksum(content); + } + useFile(file) { this.validateFileExtension(file.name); - console.log("valid file extension"); + const reader = new FileReader(); + const onLoad = this.readFile.bind(this); + reader.addEventListener("load", onLoad); + reader.readAsArrayBuffer(file); } }; var rom_default = VanillaROM; @@ -52,7 +360,7 @@ async function main() { new rom_default(); } - document.addEventListener("DOMContentLoaded", () => { + window.addEventListener("load", () => { main().catch((err) => { console.error(err); }); From 2071b64041f0621863f69887c886ff8ea0b2e18a Mon Sep 17 00:00:00 2001 From: kupppo Date: Sat, 10 Dec 2022 23:19:38 -0700 Subject: [PATCH 5/8] refactor to show alert if non-vanilla ROM --- web/js/helpers/crc32.ts | 170 +++++++++++++++++++------------------- web/js/rom.ts | 24 ++++-- web/static/customizer.js | 34 ++++---- web/views/customizer.html | 8 +- 4 files changed, 126 insertions(+), 110 deletions(-) diff --git a/web/js/helpers/crc32.ts b/web/js/helpers/crc32.ts index b1ed56838..4dc584503 100644 --- a/web/js/helpers/crc32.ts +++ b/web/js/helpers/crc32.ts @@ -1,89 +1,93 @@ -"use strict" +'use strict' + class Crc32 { - constructor() { - this.crc = -1 >>> 0; + crc: number + + constructor() { + this.crc = -1 >>> 0 + } + + update(data) { + var dataView = new Uint8Array(data, 0) + var length = dataView.length + for (var i = 0; i < length; i++) { + this.crc = (this.crc >>> 8) ^ LOOKUP[(this.crc ^ dataView[i]) & 0xFF] } - update(data) { - var dataView = new Uint8Array(data, 0); - var len = dataView.length; - for (var i = 0; i < len; i++) { - this.crc = (this.crc >>> 8) ^ Crc32.lookup[(this.crc ^ dataView[i]) & 0xFF]; - } - }; - digest(s) { - s = s || 16; - var buffer = new ArrayBuffer(4); - var dv = new DataView(buffer); - dv.setUint32(0, ~this.crc >>> 0, false); - return dv.getUint32(0).toString(s); - }; + } + + digest(size = 16) { + var buffer = new ArrayBuffer(4) + var dataView = new DataView(buffer) + dataView.setUint32(0, ~this.crc >>> 0, false) + return dataView.getUint32(0).toString(size) + } } -Crc32.lookup = [ - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, - 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, - 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, - 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, - 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, - 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, - 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, - 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, - 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, - 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, - 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, - 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, - 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, - 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, - 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, - 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, - 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, - 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, - 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, - 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, - 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, - 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, - 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, - 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, - 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, - 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, - 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, - 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, - 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, - 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, - 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, - 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, - 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, - 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, - 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, - 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, - 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, - 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, - 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, - 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, - 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, - 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, - 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, - 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, - 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, - 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, - 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, - 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, - 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, - 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, - 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, - 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, - 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, - 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, - 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, - 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, - 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, - 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, - 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, - 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, - 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, - 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D -]; +const LOOKUP = [ + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, + 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, + 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, + 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, + 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, + 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, + 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, + 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, + 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, + 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, + 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, + 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, + 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, + 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, + 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, + 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, + 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, + 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, + 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, + 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, + 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, + 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +] export default Crc32 diff --git a/web/js/rom.ts b/web/js/rom.ts index 78f46a6b9..fe0be2f36 100644 --- a/web/js/rom.ts +++ b/web/js/rom.ts @@ -14,6 +14,12 @@ class VanillaROM { return } const settings = Settings() + // TODO: - if permalink + // - and valid contents + // - then show that ROM is stored + // - else + // - show correct upload button + const selector = settings.permalink ? 'vanillaUploadFile' : 'uploadFile' this.el = document.getElementById(selector) const useFile = this.useFile.bind(this) @@ -27,13 +33,12 @@ class VanillaROM { validateChecksum(content) { const fileSize = content.byteLength - if (fileSize === 3146240) { - console.log('potential headered ROM') + const isHeadered = fileSize === 3146240 + const isTooLarge = fileSize > 4*1024*1024 + if (isHeadered) { content = content.slice(512) - } else if (fileSize > 4*1024*1024) { + } else if (isTooLarge) { throw Error(`Filesize is too big: ${content.size.toString()}`) - } else { - console.log('correct size') } const crc32 = new Crc32() @@ -41,7 +46,8 @@ class VanillaROM { const checksum = crc32.digest() if (checksum !== VANILLA_CRC32) { - throw Error('Non-Vanilla ROM detected') + console.error('Non-Vanilla ROM detected') + return false } return true @@ -58,7 +64,11 @@ class VanillaROM { readFile(evt) { const content = evt.target.result - this.validateChecksum(content) + const validated = this.validateChecksum(content) + if (!validated) { + return alert('The file you have provided is not a valid Vanilla ROM.') + } + // save with localForage } useFile(file: File) { diff --git a/web/static/customizer.js b/web/static/customizer.js index 0b93a435d..c12f2c1ed 100644 --- a/web/static/customizer.js +++ b/web/static/customizer.js @@ -21,20 +21,19 @@ } update(data) { var dataView = new Uint8Array(data, 0); - var len = dataView.length; - for (var i = 0; i < len; i++) { - this.crc = this.crc >>> 8 ^ Crc32.lookup[(this.crc ^ dataView[i]) & 255]; + var length = dataView.length; + for (var i = 0; i < length; i++) { + this.crc = this.crc >>> 8 ^ LOOKUP[(this.crc ^ dataView[i]) & 255]; } } - digest(s) { - s = s || 16; + digest(size = 16) { var buffer = new ArrayBuffer(4); - var dv = new DataView(buffer); - dv.setUint32(0, ~this.crc >>> 0, false); - return dv.getUint32(0).toString(s); + var dataView = new DataView(buffer); + dataView.setUint32(0, ~this.crc >>> 0, false); + return dataView.getUint32(0).toString(size); } }; - Crc32.lookup = [ + var LOOKUP = [ 0, 1996959894, 3993919788, @@ -318,19 +317,19 @@ } validateChecksum(content) { const fileSize = content.byteLength; - if (fileSize === 3146240) { - console.log("potential headered ROM"); + const isHeadered = fileSize === 3146240; + const isTooLarge = fileSize > 4 * 1024 * 1024; + if (isHeadered) { content = content.slice(512); - } else if (fileSize > 4 * 1024 * 1024) { + } else if (isTooLarge) { throw Error(`Filesize is too big: ${content.size.toString()}`); - } else { - console.log("correct size"); } const crc32 = new crc32_default(); crc32.update(content); const checksum = crc32.digest(); if (checksum !== VANILLA_CRC32) { - throw Error("Non-Vanilla ROM detected"); + console.error("Non-Vanilla ROM detected"); + return false; } return true; } @@ -344,7 +343,10 @@ } readFile(evt) { const content = evt.target.result; - this.validateChecksum(content); + const validated = this.validateChecksum(content); + if (!validated) { + return alert("The file you have provided is not a valid Vanilla ROM."); + } } useFile(file) { this.validateFileExtension(file.name); diff --git a/web/views/customizer.html b/web/views/customizer.html index 473e998e8..e9f1572a5 100644 --- a/web/views/customizer.html +++ b/web/views/customizer.html @@ -1006,13 +1006,13 @@ // }); // detect beam doors patch from seed to customize - beamDoorsPatch = bytes[0x226e5] == 0x0D; + // beamDoorsPatch = bytes[0x226e5] == 0x0D; // detect area layout patch - isArea = bytes[0x788A0] == 0x2b; + // isArea = bytes[0x788A0] == 0x2b; // detect Phantoon_Eye_Door patch - isBoss = bytes[0x7ccaf] == 0x91; + // isBoss = bytes[0x7ccaf] == 0x91; - console.log("isArea: "+isArea+" isBoss: "+isBoss+" isVARIA: "+isVARIA+" isRace: "+isRace); + // console.log("isArea: "+isArea+" isBoss: "+isBoss+" isVARIA: "+isVARIA+" isRace: "+isRace); // // detect varia default patches // isVARIA = false; From 3f97978b1dad6e9d1927697d3bad1b22177356ce Mon Sep 17 00:00:00 2001 From: kupppo Date: Sun, 11 Dec 2022 10:23:15 -0700 Subject: [PATCH 6/8] method for get unheadered content --- web/js/rom.ts | 54 +++++++++++++++++++++------- web/package.json | 4 ++- web/static/customizer.js | 78 ++++++++++++++++++++++++++++++++++------ web/yarn.lock | 12 +++++++ 4 files changed, 124 insertions(+), 24 deletions(-) diff --git a/web/js/rom.ts b/web/js/rom.ts index fe0be2f36..6d5f5ce85 100644 --- a/web/js/rom.ts +++ b/web/js/rom.ts @@ -2,8 +2,10 @@ import hasFileReader from './helpers/hasFileReader' import Settings from './helpers/settings' import Crc32 from './helpers/crc32' import { VANILLA_CRC32 } from './constants' +import { get, set } from 'idb-keyval' const VALID_EXTENSIONS = ['sfc', 'smc'] +const VANILLA_ROM_KEY = 'vanillaROM' class VanillaROM { el: HTMLElement | null @@ -19,6 +21,15 @@ class VanillaROM { // - then show that ROM is stored // - else // - show correct upload button + if (settings.permalink) { + const hasROMLoaded = this.getROM().then((value) => { + if (!value) { + return false + } + const validated = this.validateChecksum(value) + return validated + }) + } const selector = settings.permalink ? 'vanillaUploadFile' : 'uploadFile' this.el = document.getElementById(selector) @@ -31,26 +42,30 @@ class VanillaROM { }) } - validateChecksum(content) { + getUnheaderedContent(content) { const fileSize = content.byteLength const isHeadered = fileSize === 3146240 + return isHeadered ? content.slice(512) : content + } + + validateChecksum(content) { + const fileSize = content.byteLength const isTooLarge = fileSize > 4*1024*1024 - if (isHeadered) { - content = content.slice(512) - } else if (isTooLarge) { - throw Error(`Filesize is too big: ${content.size.toString()}`) + if (isTooLarge) { + console.warn(`Filesize is too big: ${content.size.toString()}`) + return false } const crc32 = new Crc32() crc32.update(content) const checksum = crc32.digest() - if (checksum !== VANILLA_CRC32) { - console.error('Non-Vanilla ROM detected') - return false + if (checksum === VANILLA_CRC32) { + return true } - return true + console.warn('Non-Vanilla ROM detected') + return false } validateFileExtension(name: string) { @@ -62,13 +77,14 @@ class VanillaROM { throw Error(`Unsupported file extension: ${extension}`) } - readFile(evt) { - const content = evt.target.result + async readFile(evt) { + let content = this.getUnheaderedContent(evt.target.result) const validated = this.validateChecksum(content) if (!validated) { return alert('The file you have provided is not a valid Vanilla ROM.') } - // save with localForage + const data = new Uint8Array(content) + await this.setROM(content) } useFile(file: File) { @@ -79,6 +95,20 @@ class VanillaROM { reader.addEventListener('load', onLoad) reader.readAsArrayBuffer(file) } + + getROM() { + return get(VANILLA_ROM_KEY) + } + + setROM(content: Uint8Array) { + try { + const value = set(VANILLA_ROM_KEY, content) + return value + } catch (err) { + console.error('Could not set Vanilla ROM', err) + } + + } } export default VanillaROM diff --git a/web/package.json b/web/package.json index cc10c4034..d28609961 100644 --- a/web/package.json +++ b/web/package.json @@ -9,5 +9,7 @@ "devDependencies": { "esbuild": "^0.14.48" }, - "dependencies": {} + "dependencies": { + "idb-keyval": "^6.2.0" + } } diff --git a/web/static/customizer.js b/web/static/customizer.js index c12f2c1ed..7a6725af0 100644 --- a/web/static/customizer.js +++ b/web/static/customizer.js @@ -296,8 +296,39 @@ // js/constants.ts var VANILLA_CRC32 = "d63ed5f8"; + // node_modules/idb-keyval/dist/index.js + function promisifyRequest(request) { + return new Promise((resolve, reject) => { + request.oncomplete = request.onsuccess = () => resolve(request.result); + request.onabort = request.onerror = () => reject(request.error); + }); + } + function createStore(dbName, storeName) { + const request = indexedDB.open(dbName); + request.onupgradeneeded = () => request.result.createObjectStore(storeName); + const dbp = promisifyRequest(request); + return (txMode, callback) => dbp.then((db) => callback(db.transaction(storeName, txMode).objectStore(storeName))); + } + var defaultGetStoreFunc; + function defaultGetStore() { + if (!defaultGetStoreFunc) { + defaultGetStoreFunc = createStore("keyval-store", "keyval"); + } + return defaultGetStoreFunc; + } + function get(key, customStore = defaultGetStore()) { + return customStore("readonly", (store) => promisifyRequest(store.get(key))); + } + function set(key, value, customStore = defaultGetStore()) { + return customStore("readwrite", (store) => { + store.put(value, key); + return promisifyRequest(store.transaction); + }); + } + // js/rom.ts var VALID_EXTENSIONS = ["sfc", "smc"]; + var VANILLA_ROM_KEY = "vanillaROM"; var VanillaROM = class { constructor() { if (!hasFileReader_default()) { @@ -305,6 +336,15 @@ return; } const settings = settings_default(); + if (settings.permalink) { + const hasROMLoaded = this.getROM().then((value) => { + if (!value) { + return false; + } + const validated = this.validateChecksum(value); + return validated; + }); + } const selector = settings.permalink ? "vanillaUploadFile" : "uploadFile"; this.el = document.getElementById(selector); const useFile = this.useFile.bind(this); @@ -315,23 +355,26 @@ } }); } - validateChecksum(content) { + getUnheaderedContent(content) { const fileSize = content.byteLength; const isHeadered = fileSize === 3146240; + return isHeadered ? content.slice(512) : content; + } + validateChecksum(content) { + const fileSize = content.byteLength; const isTooLarge = fileSize > 4 * 1024 * 1024; - if (isHeadered) { - content = content.slice(512); - } else if (isTooLarge) { - throw Error(`Filesize is too big: ${content.size.toString()}`); + if (isTooLarge) { + console.warn(`Filesize is too big: ${content.size.toString()}`); + return false; } const crc32 = new crc32_default(); crc32.update(content); const checksum = crc32.digest(); - if (checksum !== VANILLA_CRC32) { - console.error("Non-Vanilla ROM detected"); - return false; + if (checksum === VANILLA_CRC32) { + return true; } - return true; + console.warn("Non-Vanilla ROM detected"); + return false; } validateFileExtension(name) { const lastDot = name.lastIndexOf("."); @@ -341,12 +384,14 @@ } throw Error(`Unsupported file extension: ${extension}`); } - readFile(evt) { - const content = evt.target.result; + async readFile(evt) { + let content = this.getUnheaderedContent(evt.target.result); const validated = this.validateChecksum(content); if (!validated) { return alert("The file you have provided is not a valid Vanilla ROM."); } + const data = new Uint8Array(content); + await this.setROM(content); } useFile(file) { this.validateFileExtension(file.name); @@ -355,6 +400,17 @@ reader.addEventListener("load", onLoad); reader.readAsArrayBuffer(file); } + getROM() { + return get(VANILLA_ROM_KEY); + } + setROM(content) { + try { + const value = set(VANILLA_ROM_KEY, content); + return value; + } catch (err) { + console.error("Could not set Vanilla ROM", err); + } + } }; var rom_default = VanillaROM; diff --git a/web/yarn.lock b/web/yarn.lock index c057d3aa4..6e5d3d44f 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -127,3 +127,15 @@ esbuild@^0.14.48: esbuild-windows-32 "0.14.48" esbuild-windows-64 "0.14.48" esbuild-windows-arm64 "0.14.48" + +idb-keyval@^6.2.0: + version "6.2.0" + resolved "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.0.tgz#3af94a3cc0689d6ee0bc9e045d2a3340ea897173" + integrity sha512-uw+MIyQn2jl3+hroD7hF8J7PUviBU7BPKWw4f/ISf32D4LoGu98yHjrzWWJDASu9QNrX10tCJqk9YY0ClWm8Ng== + dependencies: + safari-14-idb-fix "^3.0.0" + +safari-14-idb-fix@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/safari-14-idb-fix/-/safari-14-idb-fix-3.0.0.tgz#450fc049b996ec7f3fd9ca2f89d32e0761583440" + integrity sha512-eBNFLob4PMq8JA1dGyFn6G97q3/WzNtFK4RnzT1fnLq+9RyrGknzYiM/9B12MnKAxuj1IXr7UKYtTNtjyKMBog== From 6ac12433cbb5911c00096ba1aecd6e3cd75ec365 Mon Sep 17 00:00:00 2001 From: kupppo Date: Sun, 11 Dec 2022 22:53:12 -0700 Subject: [PATCH 7/8] integrate vanilla ROM state for inline scripts --- web/js/rom.ts | 99 ++++++++++++++++++++++++++++++++------- web/static/customizer.js | 80 ++++++++++++++++++++++++++----- web/views/customizer.html | 21 --------- 3 files changed, 150 insertions(+), 50 deletions(-) diff --git a/web/js/rom.ts b/web/js/rom.ts index 6d5f5ce85..6b23515a5 100644 --- a/web/js/rom.ts +++ b/web/js/rom.ts @@ -2,11 +2,20 @@ import hasFileReader from './helpers/hasFileReader' import Settings from './helpers/settings' import Crc32 from './helpers/crc32' import { VANILLA_CRC32 } from './constants' -import { get, set } from 'idb-keyval' +import { del, get, set } from 'idb-keyval' const VALID_EXTENSIONS = ['sfc', 'smc'] const VANILLA_ROM_KEY = 'vanillaROM' +declare global { + interface Window { + // the /randomizer route uses the variable `vanillaROM` + vanillaROM: Uint8Array | null + // the /customizer route uses the variable `vanillaROMBytes` + vanillaROMBytes: Uint8Array | null + } +} + class VanillaROM { el: HTMLElement | null @@ -15,22 +24,21 @@ class VanillaROM { alert('This website requires the HTML5 File API, please upgrade your browser to a newer version.') return } - const settings = Settings() - // TODO: - if permalink - // - and valid contents - // - then show that ROM is stored - // - else - // - show correct upload button - if (settings.permalink) { - const hasROMLoaded = this.getROM().then((value) => { - if (!value) { - return false + + const checkForStoredFile = this.checkForStoredFile.bind(this) + const bindEvents = this.bindEvents + checkForStoredFile() + .then((hasFile) => { + if (hasFile) { + console.log('Vanilla ROM loaded from storage') + } else { + bindEvents() } - const validated = this.validateChecksum(value) - return validated }) - } + } + bindEvents() { + const settings = Settings() const selector = settings.permalink ? 'vanillaUploadFile' : 'uploadFile' this.el = document.getElementById(selector) const useFile = this.useFile.bind(this) @@ -42,12 +50,58 @@ class VanillaROM { }) } + checkForStoredFile(): Promise { + return new Promise((resolve, _reject) => { + this.getROM() + .then((value) => { + if (!value) { + resolve(false) + return + } + const validated = this.validateChecksum(value) + if (validated) { + this.broadcastROMStatus(value) + resolve(true) + return + } + throw Error('Invalid Vanilla ROM value stored') + }) + .catch((err) => { + console.error(err) + del(VANILLA_ROM_KEY) + resolve(false) + }) + }) + } + + displayStatus(hasROM = false) { + const formEl = document.getElementById('vanillaROMVisibility') + const okEl = document.getElementById('vanillaROMOKVisibility') + if (!formEl || !okEl) { + return + } + if (hasROM) { + formEl.style.display = 'none' + okEl.style.display = 'block' + } else { + formEl.style.display = 'block' + okEl.style.display = 'none' + } + + } + getUnheaderedContent(content) { const fileSize = content.byteLength const isHeadered = fileSize === 3146240 return isHeadered ? content.slice(512) : content } + broadcastROMStatus(content: Uint8Array | null) { + const hasROM = content !== null && content.byteLength > 0 + this.displayStatus(hasROM) + this.setLegacyROMToBrowser(content) + } + validateChecksum(content) { const fileSize = content.byteLength const isTooLarge = fileSize > 4*1024*1024 @@ -84,7 +138,10 @@ class VanillaROM { return alert('The file you have provided is not a valid Vanilla ROM.') } const data = new Uint8Array(content) - await this.setROM(content) + const saved = await this.setROM(data) + if (saved) { + this.broadcastROMStatus(data) + } } useFile(file: File) { @@ -102,13 +159,21 @@ class VanillaROM { setROM(content: Uint8Array) { try { - const value = set(VANILLA_ROM_KEY, content) - return value + set(VANILLA_ROM_KEY, content) + return true } catch (err) { console.error('Could not set Vanilla ROM', err) + return false } } + + setLegacyROMToBrowser(content) { + // Inline scripts on the page uses these variables depending on the route. + // This method sets both values for both variables to work with the inline scripts. + window.vanillaROMBytes = content + window.vanillaROM = content + } } export default VanillaROM diff --git a/web/static/customizer.js b/web/static/customizer.js index 7a6725af0..36af39fe7 100644 --- a/web/static/customizer.js +++ b/web/static/customizer.js @@ -325,6 +325,12 @@ return promisifyRequest(store.transaction); }); } + function del(key, customStore = defaultGetStore()) { + return customStore("readwrite", (store) => { + store.delete(key); + return promisifyRequest(store.transaction); + }); + } // js/rom.ts var VALID_EXTENSIONS = ["sfc", "smc"]; @@ -335,16 +341,18 @@ alert("This website requires the HTML5 File API, please upgrade your browser to a newer version."); return; } + const checkForStoredFile = this.checkForStoredFile.bind(this); + const bindEvents = this.bindEvents; + checkForStoredFile().then((hasFile) => { + if (hasFile) { + console.log("Vanilla ROM loaded from storage"); + } else { + bindEvents(); + } + }); + } + bindEvents() { const settings = settings_default(); - if (settings.permalink) { - const hasROMLoaded = this.getROM().then((value) => { - if (!value) { - return false; - } - const validated = this.validateChecksum(value); - return validated; - }); - } const selector = settings.permalink ? "vanillaUploadFile" : "uploadFile"; this.el = document.getElementById(selector); const useFile = this.useFile.bind(this); @@ -355,11 +363,51 @@ } }); } + checkForStoredFile() { + return new Promise((resolve, _reject) => { + this.getROM().then((value) => { + if (!value) { + resolve(false); + return; + } + const validated = this.validateChecksum(value); + if (validated) { + this.broadcastROMStatus(value); + resolve(true); + return; + } + throw Error("Invalid Vanilla ROM value stored"); + }).catch((err) => { + console.error(err); + del(VANILLA_ROM_KEY); + resolve(false); + }); + }); + } + displayStatus(hasROM = false) { + const formEl = document.getElementById("vanillaROMVisibility"); + const okEl = document.getElementById("vanillaROMOKVisibility"); + if (!formEl || !okEl) { + return; + } + if (hasROM) { + formEl.style.display = "none"; + okEl.style.display = "block"; + } else { + formEl.style.display = "block"; + okEl.style.display = "none"; + } + } getUnheaderedContent(content) { const fileSize = content.byteLength; const isHeadered = fileSize === 3146240; return isHeadered ? content.slice(512) : content; } + broadcastROMStatus(content) { + const hasROM = content !== null && content.byteLength > 0; + this.displayStatus(hasROM); + this.setLegacyROMToBrowser(content); + } validateChecksum(content) { const fileSize = content.byteLength; const isTooLarge = fileSize > 4 * 1024 * 1024; @@ -391,7 +439,10 @@ return alert("The file you have provided is not a valid Vanilla ROM."); } const data = new Uint8Array(content); - await this.setROM(content); + const saved = await this.setROM(data); + if (saved) { + this.broadcastROMStatus(data); + } } useFile(file) { this.validateFileExtension(file.name); @@ -405,12 +456,17 @@ } setROM(content) { try { - const value = set(VANILLA_ROM_KEY, content); - return value; + set(VANILLA_ROM_KEY, content); + return true; } catch (err) { console.error("Could not set Vanilla ROM", err); + return false; } } + setLegacyROMToBrowser(content) { + window.vanillaROMBytes = content; + window.vanillaROM = content; + } }; var rom_default = VanillaROM; diff --git a/web/views/customizer.html b/web/views/customizer.html index e9f1572a5..17167a103 100644 --- a/web/views/customizer.html +++ b/web/views/customizer.html @@ -1135,21 +1135,6 @@ pass }} - if(permalink == true) { - // check if a vanilla ROM is already in local storage - localforage.getItem('vanillaROM', function(err, value) { - if(err != null) { - clearLocalStorage(); - } else { - if(value != null) { - displayROMInput(false); - vanillaROMBytes = new Uint8Array(value); - } else { - clearLocalStorage(); - } - } - }); - } } function switchGamepadMapping() { @@ -1175,12 +1160,6 @@ } } -function clearLocalStorage() { - displayROMInput(true); - localforage.clear(); - vanillaROMBytes = null; -} - function permalinkCustomization(permalink) { if(permalink == true) { document.getElementById("uploadFileVisibility").style.display = "none"; From b1b7cd6e17f4acb829cb36ec41bf4ec9985d3ce2 Mon Sep 17 00:00:00 2001 From: kupppo Date: Sun, 11 Dec 2022 23:10:07 -0700 Subject: [PATCH 8/8] broadcast rom status when no rom stored --- web/js/rom.ts | 4 ++- web/static/customizer.js | 4 ++- web/views/customizer.html | 63 +-------------------------------------- 3 files changed, 7 insertions(+), 64 deletions(-) diff --git a/web/js/rom.ts b/web/js/rom.ts index 6b23515a5..0c772c29f 100644 --- a/web/js/rom.ts +++ b/web/js/rom.ts @@ -26,12 +26,14 @@ class VanillaROM { } const checkForStoredFile = this.checkForStoredFile.bind(this) - const bindEvents = this.bindEvents + const bindEvents = this.bindEvents.bind(this) + const broadcastROMStatus = this.broadcastROMStatus.bind(this) checkForStoredFile() .then((hasFile) => { if (hasFile) { console.log('Vanilla ROM loaded from storage') } else { + broadcastROMStatus(null) bindEvents() } }) diff --git a/web/static/customizer.js b/web/static/customizer.js index 36af39fe7..4d8185b71 100644 --- a/web/static/customizer.js +++ b/web/static/customizer.js @@ -342,11 +342,13 @@ return; } const checkForStoredFile = this.checkForStoredFile.bind(this); - const bindEvents = this.bindEvents; + const bindEvents = this.bindEvents.bind(this); + const broadcastROMStatus = this.broadcastROMStatus.bind(this); checkForStoredFile().then((hasFile) => { if (hasFile) { console.log("Vanilla ROM loaded from storage"); } else { + broadcastROMStatus(null); bindEvents(); } }); diff --git a/web/views/customizer.html b/web/views/customizer.html index 17167a103..ac4ff8b07 100644 --- a/web/views/customizer.html +++ b/web/views/customizer.html @@ -36,7 +36,6 @@ - @@ -944,67 +943,7 @@ pass }} window.onload = function(){ - //Check File API support - // if(window.File && window.FileList && window.FileReader) { - // if(permalink == true) { - // var inputName = "vanillaUploadFile"; - // } else { - // var inputName = "uploadFile"; - // } - // var filesInput = document.getElementById(inputName); - // filesInput.addEventListener("change", function(event){ - // var files = event.target.files; //It returns a FileList object - // var file = files[0]; - - // var reader = new FileReader(); - // reader.onload = function(e) { - // // check sfc or smc extention - // var re = /(?:\.([^.]+))?$/; - // var ext = re.exec(file.name)[1]; - // console.log("ext: "+ext) - // if( ! (ext === "sfc" || ext === "smc" || ext === "SFC" || ext === "SMC") ) { - // document.getElementById("uploadFile").value = ""; - // alert("wrong extension: "+ext); - // return false; - // } - - // romSize = file.size; - - // if(romSize == 3146240) { - // console.log("headered ROM detected, removing first 512 bytes of the header"); - // } - - // if( romSize > 4*1024*1024 ) { - // document.getElementById("uploadFile").value = ""; - // alert("wrong rom file size: "+romSize.toString()); - // return false; - // } - - // var crc32 = new Crc32(); - // crc32.update(e.target.result); - // var digest = crc32.digest(); - // console.log("crc32: "+digest); - // var isVanilla = digest == "d63ed5f8"; - - // if(permalink == true) { - // if(! isVanilla) { - // alert("Non vanilla ROM detected"); - // document.getElementById(inputName).value = ""; - // return false; - // } - - // // store file in localforage - // localforage.setItem('vanillaROM', e.target.result, function(err, value) { - // if(err != null) { - // console.log("error detected with local storage: "+err); - // clearLocalStorage(); - // } else { - // console.log("vanilla ROM stored in local storage"); - // vanillaROMBytes = new Uint8Array(value); - // displayROMInput(false); - // } - // }); - + // detect beam doors patch from seed to customize // beamDoorsPatch = bytes[0x226e5] == 0x0D; // detect area layout patch