Skip to content

feat: [UEPR-230] add sanitization when loading a project #245

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/scratch-vm/src/serialization/deserialize-assets.js
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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?
Expand Down
Binary file modified packages/scratch-vm/test/fixtures/corrupt_svg.sb2
Binary file not shown.
Binary file modified packages/scratch-vm/test/fixtures/corrupt_svg.sb3
Binary file not shown.
Binary file modified packages/scratch-vm/test/fixtures/corrupt_svg.sprite2
Binary file not shown.
Binary file modified packages/scratch-vm/test/fixtures/corrupt_svg.sprite3
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
5 changes: 3 additions & 2 deletions packages/scratch-vm/test/integration/sb2_corrupted_svg.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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 = {
Expand Down Expand Up @@ -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('<here is some')) {
if (svgString.includes('<rect width="100 height=100 fill=">')) {
throw new Error('mock createSVGSkin broke');
}
return FakeRenderer._nextSkinId++;
Expand Down
5 changes: 3 additions & 2 deletions packages/scratch-vm/test/integration/sb3_corrupted_svg.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
Expand All @@ -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('<here is some')) {
if (svgString.includes('<rect width="100 height=100 fill=">')) {
throw new Error('mock createSVGSkin broke');
}
return FakeRenderer._nextSkinId++;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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 = {
Expand Down Expand Up @@ -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('<here is some')) {
if (svgString.includes('<rect width="100 height=100 fill=">')) {
throw new Error('mock createSVGSkin broke');
}
return FakeRenderer.prototype._nextSkinId++;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
Expand All @@ -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('<here is some')) {
if (svgString.includes('<rect width="100 height=100 fill=">')) {
throw new Error('mock createSVGSkin broke');
}
return FakeRenderer.prototype._nextSkinId++;
Expand Down
Loading