diff --git a/HISTORY.md b/HISTORY.md index 0c15f042d..bd3fa7a89 100755 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,6 +1,11 @@ # Snap! (BYOB) History ## in development: +* **Notable Fixes:** + * disabled abusing the "primitive" block with metaprogramming to run arbitrary JS code. Sigh. + +### 2024-09-13 +* byob, objects, threads, store: disabled abusing the "primitive" block with metaprogramming to run arbitrary JS code. Sigh. ## 10.0.7: * **Translation Updates:** diff --git a/snap.html b/snap.html index da57ad51d..0a2450a63 100755 --- a/snap.html +++ b/snap.html @@ -17,20 +17,20 @@ - - + + - + - + diff --git a/src/byob.js b/src/byob.js index 6e3c004bf..99c506f3c 100644 --- a/src/byob.js +++ b/src/byob.js @@ -111,7 +111,7 @@ ArgLabelMorph, embedMetadataPNG, ArgMorph, RingMorph*/ // Global stuff //////////////////////////////////////////////////////// -modules.byob = '2024-August-09'; +modules.byob = '2024-September-13'; // Declarations @@ -661,6 +661,15 @@ CustomBlockDefinition.prototype.isDirectlyRecursive = function () { return this.cachedIsRecursive; }; +CustomBlockDefinition.prototype.setPrimitive = function (prim) { + if (isString(prim) && + !Object.keys(SpriteMorph.prototype.blocks).includes(prim)) { + // console.warn('attempted to set unlisted primitive:', prim); + return; + } + this.primitive = prim; +}; + // CustomBlockDefinition localizing CustomBlockDefinition.prototype.localizedSpec = function () { @@ -806,7 +815,7 @@ CustomBlockDefinition.prototype.setBlockDefinition = function (aContext) { if (body.expression?.selector === 'doPrimitive' && body.expression.inputs()[0].value ) { - this.primitive = body.expression.inputs()[1].contents().text || null; + this.setPrimitive(body.expression.inputs()[1].contents().text || null); } else { this.primitive = null; } @@ -3411,9 +3420,9 @@ BlockEditorMorph.prototype.updateDefinition = function () { if (this.definition.body?.expression?.selector === 'doPrimitive' && this.definition.body.expression.inputs()[0].value ) { - this.definition.primitive = - this.definition.body.expression.inputs()[1].contents().text - || null; + this.definition.setPrimitive( + this.definition.body.expression.inputs()[1].contents().text || null + ); } else { this.definition.primitive = null; } diff --git a/src/objects.js b/src/objects.js index df6c3b80e..06cea5d5c 100644 --- a/src/objects.js +++ b/src/objects.js @@ -96,7 +96,7 @@ CustomBlockDefinition, exportEmbroidery*/ /*jshint esversion: 11*/ -modules.objects = '2024-August-20'; +modules.objects = '2024-September-13'; var SpriteMorph; var StageMorph; @@ -2482,8 +2482,9 @@ SpriteMorph.prototype.toggleAllCustomizedPrimitives = function (stage, choice) { var prim = def.body?.expression; if (prim && prim.selector === 'doPrimitive' && prim.nextBlock()) { prim.inputs()[0].setContents(choice); - def.primitive = choice ? prim.inputs()[1].contents().text || null - : null; + def.setPrimitive( + choice ? prim.inputs()[1].contents().text || null : null + ); stage.allBlockInstances(def).reverse().forEach(block => block.selector = def.primitive || 'evaluateCustomBlock' ); diff --git a/src/store.js b/src/store.js index 6cc3538b2..e9244b8fe 100644 --- a/src/store.js +++ b/src/store.js @@ -63,7 +63,7 @@ Project*/ // Global stuff //////////////////////////////////////////////////////// -modules.store = '2024-July-24'; +modules.store = '2024-September-13'; // XML_Serializer /////////////////////////////////////////////////////// /* @@ -1052,7 +1052,7 @@ SnapSerializer.prototype.loadCustomBlocks = function ( } definition.type = child.attributes.type || 'command'; definition.selector = child.attributes.selector || null; - definition.primitive = child.attributes.primitive || null; + definition.setPrimitive(child.attributes.primitive || null); definition.isHelper = (child.attributes.helper === 'true') || false; definition.spaceAbove = (child.attributes.space === 'true') || false; definition.isGlobal = (isGlobal === true); @@ -1174,7 +1174,7 @@ SnapSerializer.prototype.loadCustomizedPrimitives = function ( } definition.type = child.attributes.type || 'command'; definition.selector = sel || null; - definition.primitive = child.attributes.primitive || null; + definition.setPrimitive(child.attributes.primitive || null); definition.isHelper = (child.attributes.helper === 'true') || false; definition.isGlobal = true; diff --git a/src/threads.js b/src/threads.js index f27969b43..07747503c 100644 --- a/src/threads.js +++ b/src/threads.js @@ -65,7 +65,7 @@ StagePickerMorph, CustomBlockDefinition, CommentMorph*/ /*jshint esversion: 11, bitwise: false, evil: true*/ -modules.threads = '2024-August-12'; +modules.threads = '2024-September-13'; var ThreadManager; var Process; @@ -8431,8 +8431,9 @@ Process.prototype.doSetBlockAttribute = function (attribute, block, val) { val = [true, 1, '1'].includes(val); if (prim && prim.selector === 'doPrimitive' && prim.nextBlock()) { prim.inputs()[0].setContents(val); - def.primitive = val ? prim.inputs()[1].contents().text || null - : null; + def.setPrimitive( + val ? prim.inputs()[1].contents().text || null : null + ); } break; case 'category':