diff --git a/package.json b/package.json index 41e12d0ac..0078f5fb4 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,6 @@ "debounce-promise": "^3.1.2", "howler": "^2.1.2", "lz-string": "^1.4.4", - "rusha": "^0.8.13", "semver": "^7.3.5" }, "devDependencies": { diff --git a/src/js/application.js b/src/js/application.js index 4e04e9c72..0985bd15a 100644 --- a/src/js/application.js +++ b/src/js/application.js @@ -36,22 +36,6 @@ import { SettingsState } from "./states/settings"; const logger = createLogger("application"); -// Set the name of the hidden property and the change event for visibility -let pageHiddenPropName, pageVisibilityEventName; -if (typeof document.hidden !== "undefined") { - // Opera 12.10 and Firefox 18 and later support - pageHiddenPropName = "hidden"; - pageVisibilityEventName = "visibilitychange"; - // @ts-ignore -} else if (typeof document.msHidden !== "undefined") { - pageHiddenPropName = "msHidden"; - pageVisibilityEventName = "msvisibilitychange"; - // @ts-ignore -} else if (typeof document.webkitHidden !== "undefined") { - pageHiddenPropName = "webkitHidden"; - pageVisibilityEventName = "webkitvisibilitychange"; -} - export class Application { /** * Boots the application @@ -176,7 +160,7 @@ export class Application { // Unload events window.addEventListener("beforeunload", this.onBeforeUnload.bind(this), true); - document.addEventListener(pageVisibilityEventName, this.handleVisibilityChange.bind(this), false); + document.addEventListener("visibilitychange", this.handleVisibilityChange.bind(this), false); // Track touches so we can update the focus appropriately document.addEventListener("touchstart", this.updateFocusAfterUserInteraction.bind(this), true); @@ -217,7 +201,7 @@ export class Application { */ handleVisibilityChange(event) { window.focus(); - const pageVisible = !document[pageHiddenPropName]; + const pageVisible = !document.hidden; if (pageVisible !== this.pageVisible) { this.pageVisible = pageVisible; logger.log("Visibility changed:", this.pageVisible); diff --git a/src/js/core/async_compression.js b/src/js/core/async_compression.js index ddc780cc9..ea5177e55 100644 --- a/src/js/core/async_compression.js +++ b/src/js/core/async_compression.js @@ -1,4 +1,4 @@ -// @ts-ignore +// @ts-expect-error FIXME: missing typings import CompressionWorker from "../webworkers/compression.worker"; import { createLogger } from "./logging"; @@ -6,26 +6,7 @@ import { round2Digits } from "./utils"; const logger = createLogger("async_compression"); -export let compressionPrefix = String.fromCodePoint(1); - -function checkCryptPrefix(prefix) { - try { - window.localStorage.setItem("prefix_test", prefix); - window.localStorage.removeItem("prefix_test"); - return true; - } catch (ex) { - logger.warn("Prefix '" + prefix + "' not available"); - return false; - } -} - -if (!checkCryptPrefix(compressionPrefix)) { - logger.warn("Switching to basic prefix"); - compressionPrefix = " "; - if (!checkCryptPrefix(compressionPrefix)) { - logger.warn("Prefix not available, ls seems to be unavailable"); - } -} +export const compressionPrefix = String.fromCodePoint(1); /** * @typedef {{ diff --git a/src/js/core/buffer_utils.js b/src/js/core/buffer_utils.js index 0048b214f..86114744d 100644 --- a/src/js/core/buffer_utils.js +++ b/src/js/core/buffer_utils.js @@ -1,6 +1,6 @@ import { globalConfig } from "./config"; -import { fastArrayDelete } from "./utils"; import { createLogger } from "./logging"; +import { fastArrayDelete } from "./utils"; const logger = createLogger("buffer_utils"); @@ -10,9 +10,6 @@ const logger = createLogger("buffer_utils"); */ export function enableImageSmoothing(context) { context.imageSmoothingEnabled = true; - context.webkitImageSmoothingEnabled = true; - - // @ts-ignore context.imageSmoothingQuality = globalConfig.smoothing.quality; } @@ -22,7 +19,6 @@ export function enableImageSmoothing(context) { */ export function disableImageSmoothing(context) { context.imageSmoothingEnabled = false; - context.webkitImageSmoothingEnabled = false; } /** diff --git a/src/js/core/config.js b/src/js/core/config.ts similarity index 93% rename from src/js/core/config.js rename to src/js/core/config.ts index 5fb7e2e1b..0e79715f7 100644 --- a/src/js/core/config.js +++ b/src/js/core/config.ts @@ -108,24 +108,16 @@ export const globalConfig = { smoothing: { smoothMainCanvas: smoothCanvas && true, - quality: "low", // Low is CRUCIAL for mobile performance! + quality: "low" as ImageSmoothingQuality, // Low is CRUCIAL for mobile performance! }, rendering: {}, debug, - currentDiscount: 0, - // Secret vars info: { // Binary file salt file: "Ec'])@^+*9zMevK3uMV4432x9%iK'=", - - // Savegame salt - sgSalt: "}95Q3%8/.837Lqym_BJx%q7)pAHJbF", - - // Analytics key - analyticsApiKey: "baf6a50f0cc7dfdec5a0e21c88a1c69a4b34bc4a", }, }; diff --git a/src/js/core/dpi_manager.js b/src/js/core/dpi_manager.js index 4fb792c0a..842dd779f 100644 --- a/src/js/core/dpi_manager.js +++ b/src/js/core/dpi_manager.js @@ -41,13 +41,9 @@ export function prepareHighDPIContext(context, smooth = true) { if (smooth) { context.imageSmoothingEnabled = true; - context.webkitImageSmoothingEnabled = true; - - // @ts-ignore context.imageSmoothingQuality = globalConfig.smoothing.quality; } else { context.imageSmoothingEnabled = false; - context.webkitImageSmoothingEnabled = false; } } diff --git a/src/js/core/polyfills.js b/src/js/core/polyfills.js index 64d175570..5f979c43e 100644 --- a/src/js/core/polyfills.js +++ b/src/js/core/polyfills.js @@ -10,79 +10,6 @@ function mathPolyfills() { }; } -function stringPolyfills() { - // https://github.com/uxitten/polyfill/blob/master/string.polyfill.js - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart - if (!String.prototype.padStart) { - String.prototype.padStart = function padStart(targetLength, padString) { - targetLength = targetLength >> 0; //truncate if number, or convert non-number to 0; - padString = String(typeof padString !== "undefined" ? padString : " "); - if (this.length >= targetLength) { - return String(this); - } else { - targetLength = targetLength - this.length; - if (targetLength > padString.length) { - padString += padString.repeat(targetLength / padString.length); //append to original to ensure we are longer than needed - } - return padString.slice(0, targetLength) + String(this); - } - }; - } - - // https://github.com/uxitten/polyfill/blob/master/string.polyfill.js - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padEnd - if (!String.prototype.padEnd) { - String.prototype.padEnd = function padEnd(targetLength, padString) { - targetLength = targetLength >> 0; //floor if number or convert non-number to 0; - padString = String(typeof padString !== "undefined" ? padString : " "); - if (this.length > targetLength) { - return String(this); - } else { - targetLength = targetLength - this.length; - if (targetLength > padString.length) { - padString += padString.repeat(targetLength / padString.length); //append to original to ensure we are longer than needed - } - return String(this) + padString.slice(0, targetLength); - } - }; - } -} - -function objectPolyfills() { - // https://github.com/tc39/proposal-object-values-entries/blob/master/polyfill.js - - // @ts-ignore - const reduce = Function.bind.call(Function.call, Array.prototype.reduce); - // @ts-ignore - const isEnumerable = Function.bind.call(Function.call, Object.prototype.propertyIsEnumerable); - // @ts-ignore - const concat = Function.bind.call(Function.call, Array.prototype.concat); - const keys = Reflect.ownKeys; - - // @ts-ignore - if (!Object.values) { - // @ts-ignore - Object.values = function values(O) { - return reduce( - keys(O), - (v, k) => concat(v, typeof k === "string" && isEnumerable(O, k) ? [O[k]] : []), - [] - ); - }; - } - - if (!Object.entries) { - // @ts-ignore - Object.entries = function entries(O) { - return reduce( - keys(O), - (e, k) => concat(e, typeof k === "string" && isEnumerable(O, k) ? [[k, O[k]]] : []), - [] - ); - }; - } -} - function domPolyfills() { // from:https://github.com/jserz/js_piece/blob/master/DOM/ChildNode/remove()/remove().md (function (arr) { @@ -104,18 +31,8 @@ function domPolyfills() { function initPolyfills() { mathPolyfills(); - stringPolyfills(); - objectPolyfills(); domPolyfills(); } -function initExtensions() { - String.prototype.replaceAll = function (search, replacement) { - var target = this; - return target.split(search).join(replacement); - }; -} - // Other polyfills initPolyfills(); -initExtensions(); diff --git a/src/js/core/read_write_proxy.js b/src/js/core/read_write_proxy.js index 9ad7a5df6..02afa2a2b 100644 --- a/src/js/core/read_write_proxy.js +++ b/src/js/core/read_write_proxy.js @@ -2,21 +2,20 @@ import { Application } from "../application"; /* typehints:end */ -import { sha1, CRC_PREFIX, computeCrc } from "./sensitive_utils.encrypt"; -import { createLogger } from "./logging"; import { FILE_NOT_FOUND } from "../platform/storage"; -import { accessNestedPropertyReverse } from "./utils"; +import { compressObject, decompressObject } from "../savegame/savegame_compressor"; +import { asyncCompressor, compressionPrefix } from "./async_compression"; import { IS_DEBUG, globalConfig } from "./config"; import { ExplainedResult } from "./explained_result"; -import { decompressX64, compressX64 } from "./lzstring"; -import { asyncCompressor, compressionPrefix } from "./async_compression"; -import { compressObject, decompressObject } from "../savegame/savegame_compressor"; +import { createLogger } from "./logging"; +import { compressX64, decompressX64 } from "./lzstring"; +import { computeCrc } from "./sensitive_utils.encrypt"; import debounce from "debounce-promise"; const logger = createLogger("read_write_proxy"); -const salt = accessNestedPropertyReverse(globalConfig, ["file", "info"]); +const salt = globalConfig.info.file; // Helper which only writes / reads if verify() works. Also performs migration export class ReadWriteProxy { @@ -110,9 +109,7 @@ export class ReadWriteProxy { const checksum = decompressed.substring(0, 40); const jsonString = decompressed.substr(40); - const desiredChecksum = checksum.startsWith(CRC_PREFIX) - ? computeCrc(jsonString + salt) - : sha1(jsonString + salt); + const desiredChecksum = computeCrc(jsonString + salt); if (desiredChecksum !== checksum) { // Checksum mismatch @@ -199,11 +196,9 @@ export class ReadWriteProxy { // Compare stored checksum with actual checksum const checksum = decompressed.substring(0, 40); - const jsonString = decompressed.substr(40); + const jsonString = decompressed.slice(40); - const desiredChecksum = checksum.startsWith(CRC_PREFIX) - ? computeCrc(jsonString + salt) - : sha1(jsonString + salt); + const desiredChecksum = computeCrc(jsonString + salt); if (desiredChecksum !== checksum) { // Checksum mismatch diff --git a/src/js/core/sensitive_utils.encrypt.js b/src/js/core/sensitive_utils.encrypt.js index 5a83bf76c..e61e0b67a 100644 --- a/src/js/core/sensitive_utils.encrypt.js +++ b/src/js/core/sensitive_utils.encrypt.js @@ -1,15 +1,4 @@ -import { createHash } from "rusha"; import crc32 from "crc/crc32"; -import { decompressX64 } from "./lzstring"; - -export function sha1(str) { - return createHash().update(str).digest("hex"); -} - -// Window.location.host -export function getNameOfProvider() { - return window[decompressX64("DYewxghgLgliB2Q")][decompressX64("BYewzgLgdghgtgUyA")]; -} // Distinguish legacy crc prefixes export const CRC_PREFIX = "crc32".padEnd(32, "-"); diff --git a/src/js/core/utils.js b/src/js/core/utils.js index 673c021f6..291b5a422 100644 --- a/src/js/core/utils.js +++ b/src/js/core/utils.js @@ -40,19 +40,6 @@ export function randomInt(start, end) { return Math.floor(Math.random() * (end - start + 1) + start); } -/** - * Access an object in a very annoying way, used for obsfuscation. - * @param {any} obj - * @param {Array} keys - */ -export function accessNestedPropertyReverse(obj, keys) { - let result = obj; - for (let i = keys.length - 1; i >= 0; --i) { - result = result[keys[i]]; - } - return result; -} - /** * Chooses a random entry of an array * @template T @@ -406,7 +393,7 @@ export function makeButton(parent, classes = [], innerHTML = "") { */ export function removeAllChildren(elem) { if (elem) { - var range = document.createRange(); + const range = document.createRange(); range.selectNodeContents(elem); range.deleteContents(); } @@ -618,7 +605,7 @@ export function fillInLinkIntoTranslation(translation, link) { * @param {string} text */ export function generateFileDownload(filename, text) { - var element = document.createElement("a"); + const element = document.createElement("a"); element.setAttribute("href", "data:text/plain;charset=utf-8," + encodeURIComponent(text)); element.setAttribute("download", filename); @@ -634,7 +621,7 @@ export function generateFileDownload(filename, text) { * @param {string} acceptedType */ export function startFileChoose(acceptedType = ".bin") { - var input = document.createElement("input"); + const input = document.createElement("input"); input.type = "file"; input.accept = acceptedType; diff --git a/src/js/core/vector.js b/src/js/core/vector.js index 50fa9433a..9525f5b3a 100644 --- a/src/js/core/vector.js +++ b/src/js/core/vector.js @@ -489,7 +489,6 @@ export class Vector { } default: { assertAlways(false, "Invalid fast inplace rotation: " + angle); - return this; } } // return new Vector(this.x * cos - this.y * sin, this.x * sin + this.y * cos); @@ -519,7 +518,6 @@ export class Vector { } default: { assertAlways(false, "Invalid fast inplace rotation: " + angle); - return new Vector(); } } } @@ -593,7 +591,6 @@ export class Vector { } default: assertAlways(false, "Invalid angle: " + angle); - return; } } @@ -603,7 +600,7 @@ export class Vector { * @returns {Boolean} */ equalsEpsilon(v, epsilon = 1e-5) { - return Math.abs(this.x - v.x) < 1e-5 && Math.abs(this.y - v.y) < epsilon; + return Math.abs(this.x - v.x) < epsilon && Math.abs(this.y - v.y) < epsilon; } /** diff --git a/src/js/globals.d.ts b/src/js/globals.d.ts index 8d62ff0f8..7176807fd 100644 --- a/src/js/globals.d.ts +++ b/src/js/globals.d.ts @@ -22,11 +22,6 @@ declare const shapez: any; declare const ipcRenderer: any; -// Polyfills -declare interface String { - replaceAll(search: string, replacement: string): string; -} - declare interface ImportMeta { webpackContext( request: string, @@ -47,10 +42,6 @@ declare interface ImportMeta { declare interface CanvasRenderingContext2D { beginRoundedRect(x: number, y: number, w: number, h: number, r: number): void; beginCircle(x: number, y: number, r: number): void; - - msImageSmoothingEnabled: boolean; - mozImageSmoothingEnabled: boolean; - webkitImageSmoothingEnabled: boolean; } // Just for compatibility with the shared code diff --git a/src/js/savegame/savegame_manager.js b/src/js/savegame/savegame_manager.js index 49443f256..b70bd8515 100644 --- a/src/js/savegame/savegame_manager.js +++ b/src/js/savegame/savegame_manager.js @@ -1,12 +1,10 @@ +import { globalConfig } from "../core/config"; import { ExplainedResult } from "../core/explained_result"; import { createLogger } from "../core/logging"; import { ReadWriteProxy } from "../core/read_write_proxy"; -import { globalConfig } from "../core/config"; import { Savegame } from "./savegame"; const logger = createLogger("savegame_manager"); -import Rusha from "rusha"; - /** * @typedef {import("./savegame_typedefs").SavegamesData} SavegamesData * @typedef {import("./savegame_typedefs").SavegameMetadata} SavegameMetadata @@ -217,9 +215,7 @@ export class SavegameManager extends ReadWriteProxy { * Helper method to generate a new internal savegame id */ generateInternalId() { - return Rusha.createHash() - .update(Date.now() + "/" + Math.random()) - .digest("hex"); + return self.crypto.randomUUID(); } // End diff --git a/src/js/states/preload.js b/src/js/states/preload.js index c58f63dac..7799d7cfc 100644 --- a/src/js/states/preload.js +++ b/src/js/states/preload.js @@ -2,10 +2,10 @@ import { CHANGELOG } from "../changelog"; import { globalConfig } from "../core/config"; import { GameState } from "../core/game_state"; import { createLogger } from "../core/logging"; -import { getLogoSprite, timeoutPromise } from "../core/utils"; +import { getLogoSprite } from "../core/utils"; import { getRandomHint } from "../game/hints"; import { HUDModalDialogs } from "../game/hud/parts/modal_dialogs"; -import { autoDetectLanguageId, T, updateApplicationLanguage } from "../translations"; +import { T, autoDetectLanguageId, updateApplicationLanguage } from "../translations"; const logger = createLogger("state/preload"); @@ -44,22 +44,6 @@ export class PreloadState extends GameState { this.startLoading(); } - async fetchDiscounts() { - await timeoutPromise( - fetch("https://analytics.shapez.io/v1/discounts") - .then(res => res.json()) - .then(data => { - globalConfig.currentDiscount = Number( - data["1318690"].data.price_overview.discount_percent - ); - logger.log("Fetched current discount:", globalConfig.currentDiscount); - }), - 2000 - ).catch(err => { - logger.warn("Failed to fetch current discount:", err); - }); - } - async sendBeacon() { // TODO: Get rid of this analytics stuff } @@ -78,9 +62,6 @@ export class PreloadState extends GameState { return this.app.storage.initialize(); }) - .then(() => this.setStatus("Connecting to api", 15)) - .then(() => this.fetchDiscounts()) - .then(() => this.setStatus("Initializing settings", 20)) .then(() => { return this.app.settings.initialize(); @@ -256,7 +237,7 @@ export class PreloadState extends GameState { subElement.innerHTML = `
diff --git a/src/js/translations.js b/src/js/translations.js index f79ea1034..c6630497f 100644 --- a/src/js/translations.js +++ b/src/js/translations.js @@ -7,7 +7,7 @@ const logger = createLogger("translations"); // @ts-ignore import baseTranslations from "./built-temp/base-en.json"; -export let T = baseTranslations; +export const T = baseTranslations; if (G_IS_DEV && globalConfig.debug.testTranslations) { // Replaces all translations by fake translations to see whats translated and what not @@ -67,18 +67,11 @@ function mapLanguageCodeToId(languageKey) { * @returns {string} */ export function autoDetectLanguageId() { - let languages = []; - if (navigator.languages) { - languages = navigator.languages.slice(); - } else if (navigator.language) { - languages = [navigator.language]; - } else { - logger.warn("Navigator has no languages prop"); - } + const languages = navigator.languages; - for (let i = 0; i < languages.length; ++i) { - logger.log("Trying to find language target for", languages[i]); - const trans = mapLanguageCodeToId(languages[i]); + for (const language of languages) { + logger.log("Trying to find language target for", language); + const trans = mapLanguageCodeToId(language); if (trans) { return trans; } diff --git a/src/js/webworkers/compression.worker.js b/src/js/webworkers/compression.worker.js index 1e567c050..e0414d7cd 100644 --- a/src/js/webworkers/compression.worker.js +++ b/src/js/webworkers/compression.worker.js @@ -3,16 +3,6 @@ import { compressX64 } from "../core/lzstring"; import { computeCrc } from "../core/sensitive_utils.encrypt"; import { compressObject } from "../savegame/savegame_compressor"; -function accessNestedPropertyReverse(obj, keys) { - let result = obj; - for (let i = keys.length - 1; i >= 0; --i) { - result = result[keys[i]]; - } - return result; -} - -const salt = accessNestedPropertyReverse(globalConfig, ["file", "info"]); - self.addEventListener("message", event => { // @ts-ignore const { jobId, job, data } = event.data; @@ -32,7 +22,7 @@ function performJob(job, data) { const optimized = compressObject(data.obj); const stringified = JSON.stringify(optimized); - const checksum = computeCrc(stringified + salt); + const checksum = computeCrc(stringified + globalConfig.info.file); return data.compressionPrefix + compressX64(checksum + stringified); } default: diff --git a/yarn.lock b/yarn.lock index 97c930cfc..3cd4bf199 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8580,11 +8580,6 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -rusha@^0.8.13: - version "0.8.14" - resolved "https://registry.yarnpkg.com/rusha/-/rusha-0.8.14.tgz#a977d0de9428406138b7bb90d3de5dcd024e2f68" - integrity sha512-cLgakCUf6PedEu15t8kbsjnwIFFR2D4RfL+W3iWFJ4iac7z4B0ZI8fxy4R3J956kAI68HclCFGL8MPoUVC3qVA== - rx-lite@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102"