|
|
@ -2,7 +2,7 @@
|
|
|
|
import { Application } from "../application";
|
|
|
|
import { Application } from "../application";
|
|
|
|
/* typehints:end */
|
|
|
|
/* typehints:end */
|
|
|
|
|
|
|
|
|
|
|
|
import { sha1 } from "./sensitive_utils.encrypt";
|
|
|
|
import { sha1, CRC_PREFIX } from "./sensitive_utils.encrypt";
|
|
|
|
import { createLogger } from "./logging";
|
|
|
|
import { createLogger } from "./logging";
|
|
|
|
import { FILE_NOT_FOUND } from "../platform/storage";
|
|
|
|
import { FILE_NOT_FOUND } from "../platform/storage";
|
|
|
|
import { accessNestedPropertyReverse } from "./utils";
|
|
|
|
import { accessNestedPropertyReverse } from "./utils";
|
|
|
@ -11,6 +11,7 @@ import { ExplainedResult } from "./explained_result";
|
|
|
|
import { decompressX64, compressX64 } from "./lzstring";
|
|
|
|
import { decompressX64, compressX64 } from "./lzstring";
|
|
|
|
import { asyncCompressor, compressionPrefix } from "./async_compression";
|
|
|
|
import { asyncCompressor, compressionPrefix } from "./async_compression";
|
|
|
|
import { compressObject, decompressObject } from "../savegame/savegame_compressor";
|
|
|
|
import { compressObject, decompressObject } from "../savegame/savegame_compressor";
|
|
|
|
|
|
|
|
import crc32 from "crc/crc32";
|
|
|
|
|
|
|
|
|
|
|
|
const logger = createLogger("read_write_proxy");
|
|
|
|
const logger = createLogger("read_write_proxy");
|
|
|
|
|
|
|
|
|
|
|
@ -84,7 +85,7 @@ export class ReadWriteProxy {
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
static serializeObject(obj) {
|
|
|
|
static serializeObject(obj) {
|
|
|
|
const jsonString = JSON.stringify(compressObject(obj));
|
|
|
|
const jsonString = JSON.stringify(compressObject(obj));
|
|
|
|
const checksum = sha1(jsonString + salt);
|
|
|
|
const checksum = CRC_PREFIX + crc32(jsonString + salt).toString(16);
|
|
|
|
return compressionPrefix + compressX64(checksum + jsonString);
|
|
|
|
return compressionPrefix + compressX64(checksum + jsonString);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -106,7 +107,11 @@ export class ReadWriteProxy {
|
|
|
|
// Compare stored checksum with actual checksum
|
|
|
|
// Compare stored checksum with actual checksum
|
|
|
|
const checksum = decompressed.substring(0, 40);
|
|
|
|
const checksum = decompressed.substring(0, 40);
|
|
|
|
const jsonString = decompressed.substr(40);
|
|
|
|
const jsonString = decompressed.substr(40);
|
|
|
|
const desiredChecksum = sha1(jsonString + salt);
|
|
|
|
|
|
|
|
|
|
|
|
const desiredChecksum = checksum.startsWith(CRC_PREFIX)
|
|
|
|
|
|
|
|
? CRC_PREFIX + crc32(jsonString + salt).toString(16)
|
|
|
|
|
|
|
|
: sha1(jsonString + salt);
|
|
|
|
|
|
|
|
|
|
|
|
if (desiredChecksum !== checksum) {
|
|
|
|
if (desiredChecksum !== checksum) {
|
|
|
|
// Checksum mismatch
|
|
|
|
// Checksum mismatch
|
|
|
|
throw new Error("bad-content / checksum-mismatch");
|
|
|
|
throw new Error("bad-content / checksum-mismatch");
|
|
|
@ -119,7 +124,7 @@ export class ReadWriteProxy {
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Writes the data asychronously, fails if verify() fails
|
|
|
|
* Writes the data asychronously, fails if verify() fails
|
|
|
|
* @returns {Promise<string>}
|
|
|
|
* @returns {Promise<void>}
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
writeAsync() {
|
|
|
|
writeAsync() {
|
|
|
|
const verifyResult = this.internalVerifyEntry(this.currentData);
|
|
|
|
const verifyResult = this.internalVerifyEntry(this.currentData);
|
|
|
@ -128,35 +133,14 @@ export class ReadWriteProxy {
|
|
|
|
logger.error("Tried to write invalid data to", this.filename, "reason:", verifyResult.reason);
|
|
|
|
logger.error("Tried to write invalid data to", this.filename, "reason:", verifyResult.reason);
|
|
|
|
return Promise.reject(verifyResult.reason);
|
|
|
|
return Promise.reject(verifyResult.reason);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const jsonString = JSON.stringify(compressObject(this.currentData));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if (!this.app.pageVisible || this.app.unloaded) {
|
|
|
|
|
|
|
|
// logger.log("Saving file sync because in unload handler");
|
|
|
|
|
|
|
|
// const checksum = sha1(jsonString + salt);
|
|
|
|
|
|
|
|
// let compressed = compressionPrefix + compressX64(checksum + jsonString);
|
|
|
|
|
|
|
|
// if (G_IS_DEV && IS_DEBUG) {
|
|
|
|
|
|
|
|
// compressed = jsonString;
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if (!this.app.storage.writeFileSyncIfSupported(this.filename, compressed)) {
|
|
|
|
|
|
|
|
// return Promise.reject("Failed to write " + this.filename + " sync!");
|
|
|
|
|
|
|
|
// } else {
|
|
|
|
|
|
|
|
// logger.log("📄 Wrote (sync!)", this.filename);
|
|
|
|
|
|
|
|
// return Promise.resolve(compressed);
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return asyncCompressor
|
|
|
|
return asyncCompressor
|
|
|
|
.compressFileAsync(jsonString)
|
|
|
|
.compressObjectAsync(this.currentData)
|
|
|
|
.then(compressed => {
|
|
|
|
.then(compressed => {
|
|
|
|
if (G_IS_DEV && IS_DEBUG) {
|
|
|
|
|
|
|
|
compressed = jsonString;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.app.storage.writeFileAsync(this.filename, compressed);
|
|
|
|
return this.app.storage.writeFileAsync(this.filename, compressed);
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.then(() => {
|
|
|
|
.then(() => {
|
|
|
|
logger.log("📄 Wrote", this.filename);
|
|
|
|
logger.log("📄 Wrote", this.filename);
|
|
|
|
return jsonString;
|
|
|
|
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.catch(err => {
|
|
|
|
.catch(err => {
|
|
|
|
logger.error("Failed to write", this.filename, ":", err);
|
|
|
|
logger.error("Failed to write", this.filename, ":", err);
|
|
|
@ -205,7 +189,11 @@ export class ReadWriteProxy {
|
|
|
|
// Compare stored checksum with actual checksum
|
|
|
|
// Compare stored checksum with actual checksum
|
|
|
|
const checksum = decompressed.substring(0, 40);
|
|
|
|
const checksum = decompressed.substring(0, 40);
|
|
|
|
const jsonString = decompressed.substr(40);
|
|
|
|
const jsonString = decompressed.substr(40);
|
|
|
|
const desiredChecksum = sha1(jsonString + salt);
|
|
|
|
|
|
|
|
|
|
|
|
const desiredChecksum = checksum.startsWith(CRC_PREFIX)
|
|
|
|
|
|
|
|
? CRC_PREFIX + crc32(jsonString + salt).toString(16)
|
|
|
|
|
|
|
|
: sha1(jsonString + salt);
|
|
|
|
|
|
|
|
|
|
|
|
if (desiredChecksum !== checksum) {
|
|
|
|
if (desiredChecksum !== checksum) {
|
|
|
|
// Checksum mismatch
|
|
|
|
// Checksum mismatch
|
|
|
|
return Promise.reject("bad-content / checksum-mismatch");
|
|
|
|
return Promise.reject("bad-content / checksum-mismatch");
|
|
|
|