diff --git a/packages/scratch-vm/src/serialization/deserialize-assets.js b/packages/scratch-vm/src/serialization/deserialize-assets.js index 568614c3dc..c1e85c6d4a 100644 --- a/packages/scratch-vm/src/serialization/deserialize-assets.js +++ b/packages/scratch-vm/src/serialization/deserialize-assets.js @@ -1,5 +1,6 @@ const JSZip = require('jszip'); const log = require('../util/log'); +const {sanitizeSvg} = require('@scratch/scratch-svg-renderer'); /** * Deserializes sound from file into storage cache so that it can @@ -156,6 +157,11 @@ const deserializeCostume = function (costume, runtime, zip, assetFileName, textL return Promise.all([textLayerFilePromise, costumeFile.async('uint8array') + .then(data => + (costumeFormat === 'svg' ? + sanitizeSvg.sanitizeByteStream(data) : + data) + ) .then(data => storage.createAsset( assetType, // TODO eventually we want to map non-png's to their actual file types? diff --git a/packages/scratch-vm/test/fixtures/corrupt_svg.sb2 b/packages/scratch-vm/test/fixtures/corrupt_svg.sb2 index 4290c1bfcd..065f7127a7 100644 Binary files a/packages/scratch-vm/test/fixtures/corrupt_svg.sb2 and b/packages/scratch-vm/test/fixtures/corrupt_svg.sb2 differ diff --git a/packages/scratch-vm/test/fixtures/corrupt_svg.sb3 b/packages/scratch-vm/test/fixtures/corrupt_svg.sb3 index 52fb93096f..5a7914ada1 100644 Binary files a/packages/scratch-vm/test/fixtures/corrupt_svg.sb3 and b/packages/scratch-vm/test/fixtures/corrupt_svg.sb3 differ diff --git a/packages/scratch-vm/test/fixtures/corrupt_svg.sprite2 b/packages/scratch-vm/test/fixtures/corrupt_svg.sprite2 index 0db0dd70b9..ed846d00e9 100644 Binary files a/packages/scratch-vm/test/fixtures/corrupt_svg.sprite2 and b/packages/scratch-vm/test/fixtures/corrupt_svg.sprite2 differ diff --git a/packages/scratch-vm/test/fixtures/corrupt_svg.sprite3 b/packages/scratch-vm/test/fixtures/corrupt_svg.sprite3 index 1d9dd0b3dd..5be5353d9e 100644 Binary files a/packages/scratch-vm/test/fixtures/corrupt_svg.sprite3 and b/packages/scratch-vm/test/fixtures/corrupt_svg.sprite3 differ diff --git a/packages/scratch-vm/test/integration/monitors_sb2_to_sb3.js b/packages/scratch-vm/test/integration/monitors_sb2_to_sb3.js index 77b67bce85..ffd52399af 100644 --- a/packages/scratch-vm/test/integration/monitors_sb2_to_sb3.js +++ b/packages/scratch-vm/test/integration/monitors_sb2_to_sb3.js @@ -4,40 +4,25 @@ const makeTestStorage = require('../fixtures/make-test-storage'); const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer; const VirtualMachine = require('../../src/index'); -let vm; +const projectUri = path.resolve(__dirname, '../fixtures/monitors.sb2'); +const project = readFileToBuffer(projectUri); -tap.beforeEach(() => { - const projectUri = path.resolve(__dirname, '../fixtures/monitors.sb2'); - const project = readFileToBuffer(projectUri); - - vm = new VirtualMachine(); - vm.attachStorage(makeTestStorage()); - - // TODO figure out why running threads doesn't work in this test - // vm.start(); - vm.clear(); - vm.setCompatibilityMode(false); - vm.setTurboMode(false); - - return vm.loadProject(project); -}); const test = tap.test; test('saving and loading sb2 project with monitors preserves sliderMin and sliderMax', t => { + const vm = new VirtualMachine(); + vm.attachStorage(makeTestStorage()); vm.on('playgroundData', e /* eslint-disable-line no-unused-vars */ => { - // TODO related to above TODO, comment these back in when we figure out - // why running threads doesn't work with this test - - // const threads = JSON.parse(e.threads); + const threads = JSON.parse(e.threads); // All monitors should create threads that finish during the step and // are revoved from runtime.threads. - // t.equal(threads.length, 0); + t.equal(threads.length, 0); // we care that the last step updated the right number of monitors // we don't care whether the last step ran other threads or not - // const lastStepUpdatedMonitorThreads = vm.runtime._lastStepDoneThreads.filter(thread => thread.updateMonitor); - // t.equal(lastStepUpdatedMonitorThreads.length, 8); + const lastStepUpdatedMonitorThreads = vm.runtime._lastStepDoneThreads.filter(thread => thread.updateMonitor); + t.equal(lastStepUpdatedMonitorThreads.length, 8); // There should be one additional hidden monitor that is in the monitorState but // does not start a thread. @@ -139,13 +124,18 @@ test('saving and loading sb2 project with monitors preserves sliderMin and slide t.equal(monitorRecord.spriteName, null); t.equal(monitorRecord.targetId, null); + vm.quit(); t.end(); }); // Start VM, load project, and run t.doesNotThrow(() => { - const sb3ProjectJson = vm.toJSON(); - return vm.loadProject(sb3ProjectJson).then(() => { + vm.start(); + vm.clear(); + vm.setCompatibilityMode(false); + vm.setTurboMode(false); + return vm.loadProject(project).then(() => { + vm.greenFlag(); setTimeout(() => { vm.getPlaygroundData(); vm.stopAll(); diff --git a/packages/scratch-vm/test/integration/offline-custom-assets.js b/packages/scratch-vm/test/integration/offline-custom-assets.js index d52dda6d61..42d890a73c 100644 --- a/packages/scratch-vm/test/integration/offline-custom-assets.js +++ b/packages/scratch-vm/test/integration/offline-custom-assets.js @@ -10,6 +10,7 @@ const test = require('tap').test; const AdmZip = require('adm-zip'); const ScratchStorage = require('scratch-storage').ScratchStorage; const VirtualMachine = require('../../src/index'); +const {sanitizeByteStream} = require('../../../scratch-svg-renderer/src/sanitize-svg'); const projectUri = path.resolve(__dirname, '../fixtures/offline-custom-assets.sb2'); const projectZip = AdmZip(projectUri); @@ -54,7 +55,7 @@ test('offline-custom-assets', t => { const storedCostume = customCostume.asset; t.type(storedCostume, 'object'); - t.deepEquals(storedCostume.data, costumeData); + t.same(storedCostume.data, sanitizeByteStream(costumeData)); const sounds = vm.runtime.targets[1].sprite.sounds; t.equals(sounds.length, 1); diff --git a/packages/scratch-vm/test/integration/sb2_corrupted_svg.js b/packages/scratch-vm/test/integration/sb2_corrupted_svg.js index 5ad71fa17c..672a6cf1fb 100644 --- a/packages/scratch-vm/test/integration/sb2_corrupted_svg.js +++ b/packages/scratch-vm/test/integration/sb2_corrupted_svg.js @@ -15,6 +15,7 @@ const FakeBitmapAdapter = require('../fixtures/fake-bitmap-adapter'); const {extractAsset, readFileToBuffer} = require('../fixtures/readProjectFile'); const VirtualMachine = require('../../src/index'); const {serializeCostumes} = require('../../src/serialization/serialize-assets'); +const {sanitizeByteStream} = require('../../../scratch-svg-renderer/src/sanitize-svg'); const projectUri = path.resolve(__dirname, '../fixtures/corrupt_svg.sb2'); const project = readFileToBuffer(projectUri); @@ -23,7 +24,7 @@ const originalCostume = extractAsset(projectUri, costumeFileName); // We need to get the actual md5 because we hand modified the svg to corrupt it // after we downloaded the project from Scratch // Loading the project back into the VM will correct the assetId and md5 -const brokenCostumeMd5 = md5(originalCostume); +const brokenCostumeMd5 = md5(sanitizeByteStream(originalCostume)); global.Image = function () { const image = { @@ -57,7 +58,7 @@ tap.beforeEach(() => { // Mock renderer breaking on loading a corrupt costume FakeRenderer.prototype.createSVGSkin = function (svgString) { // Look for text added to costume to make it a corrupt svg - if (svgString.includes('')) { throw new Error('mock createSVGSkin broke'); } return FakeRenderer._nextSkinId++; diff --git a/packages/scratch-vm/test/integration/sb3_corrupted_svg.js b/packages/scratch-vm/test/integration/sb3_corrupted_svg.js index d4efe3653d..f8c8e4b268 100644 --- a/packages/scratch-vm/test/integration/sb3_corrupted_svg.js +++ b/packages/scratch-vm/test/integration/sb3_corrupted_svg.js @@ -14,6 +14,7 @@ const FakeRenderer = require('../fixtures/fake-renderer'); const {extractAsset, readFileToBuffer} = require('../fixtures/readProjectFile'); const VirtualMachine = require('../../src/index'); const {serializeCostumes} = require('../../src/serialization/serialize-assets'); +const {sanitizeByteStream} = require('../../../scratch-svg-renderer/src/sanitize-svg'); const projectUri = path.resolve(__dirname, '../fixtures/corrupt_svg.sb3'); const project = readFileToBuffer(projectUri); @@ -22,7 +23,7 @@ const originalCostume = extractAsset(projectUri, costumeFileName); // We need to get the actual md5 because we hand modified the svg to corrupt it // after we downloaded the project from Scratch // Loading the project back into the VM will correct the assetId and md5 -const brokenCostumeMd5 = md5(originalCostume); +const brokenCostumeMd5 = md5(sanitizeByteStream(originalCostume)); let vm; let defaultVectorAssetId; @@ -37,7 +38,7 @@ tap.beforeEach(() => { // Mock renderer breaking on loading a corrupt costume FakeRenderer.prototype.createSVGSkin = function (svgString) { // Look for text added to costume to make it a corrupt svg - if (svgString.includes('')) { throw new Error('mock createSVGSkin broke'); } return FakeRenderer._nextSkinId++; diff --git a/packages/scratch-vm/test/integration/sprite2_corrupted_svg.js b/packages/scratch-vm/test/integration/sprite2_corrupted_svg.js index 866448d797..b7776435d2 100644 --- a/packages/scratch-vm/test/integration/sprite2_corrupted_svg.js +++ b/packages/scratch-vm/test/integration/sprite2_corrupted_svg.js @@ -16,6 +16,7 @@ const FakeBitmapAdapter = require('../fixtures/fake-bitmap-adapter'); const {extractAsset, readFileToBuffer} = require('../fixtures/readProjectFile'); const VirtualMachine = require('../../src/index'); const {serializeCostumes} = require('../../src/serialization/serialize-assets'); +const {sanitizeByteStream} = require('../../../scratch-svg-renderer/src/sanitize-svg'); const projectUri = path.resolve(__dirname, '../fixtures/default.sb3'); const project = readFileToBuffer(projectUri); @@ -28,7 +29,7 @@ const originalCostume = extractAsset(spriteUri, costumeFileName); // We need to get the actual md5 because we hand modified the svg to corrupt it // after we downloaded the project from Scratch // Loading the project back into the VM will correct the assetId and md5 -const brokenCostumeMd5 = md5(originalCostume); +const brokenCostumeMd5 = md5(sanitizeByteStream(originalCostume)); global.Image = function () { const image = { @@ -61,7 +62,7 @@ tap.beforeEach(() => { // Mock renderer breaking on loading a corrupt costume FakeRenderer.prototype.createSVGSkin = function (svgString) { // Look for text added to costume to make it a corrupt svg - if (svgString.includes('')) { throw new Error('mock createSVGSkin broke'); } return FakeRenderer.prototype._nextSkinId++; diff --git a/packages/scratch-vm/test/integration/sprite3_corrupted_svg.js b/packages/scratch-vm/test/integration/sprite3_corrupted_svg.js index f78f468a06..6d2da371dd 100644 --- a/packages/scratch-vm/test/integration/sprite3_corrupted_svg.js +++ b/packages/scratch-vm/test/integration/sprite3_corrupted_svg.js @@ -15,6 +15,7 @@ const FakeRenderer = require('../fixtures/fake-renderer'); const {extractAsset, readFileToBuffer} = require('../fixtures/readProjectFile'); const VirtualMachine = require('../../src/index'); const {serializeCostumes} = require('../../src/serialization/serialize-assets'); +const {sanitizeByteStream} = require('../../../scratch-svg-renderer/src/sanitize-svg'); const projectUri = path.resolve(__dirname, '../fixtures/default.sb3'); const project = readFileToBuffer(projectUri); @@ -27,7 +28,7 @@ const originalCostume = extractAsset(spriteUri, costumeFileName); // We need to get the actual md5 because we hand modified the svg to corrupt it // after we downloaded the project from Scratch // Loading the project back into the VM will correct the assetId and md5 -const brokenCostumeMd5 = md5(originalCostume); +const brokenCostumeMd5 = md5(sanitizeByteStream(originalCostume)); let vm; let defaultVectorAssetId; @@ -42,7 +43,7 @@ tap.beforeEach(() => { // Mock renderer breaking on loading a corrupt costume FakeRenderer.prototype.createSVGSkin = function (svgString) { // Look for text added to costume to make it a corrupt svg - if (svgString.includes('')) { throw new Error('mock createSVGSkin broke'); } return FakeRenderer.prototype._nextSkinId++;