Files
scratch-vm/test/integration/tw_privacy.js
T
GarboMuffin 2b265e55a0 Disable private skin access when cloud variables or custom extensions are used
This is a breaking change.
Replaces logic that was previously in our scratch-gui fork.
Upstream does the opposite; they disable cloud variables when video
sensing is used. We can't do the same because of custom extensions.
Disabling all custom extensions when video sensing is used would be too
limiting. The concern with custom extensions is not that they will steal
private skins, but that a project could use their blocks to fetch()
color information to a remote server similar to cloud variables.
The end result is not dissimilar: Cloud variables and video sensing
shouldn't be used together.
2022-11-16 20:52:31 -06:00

117 lines
3.3 KiB
JavaScript

const {test} = require('tap');
const Runtime = require('../../src/engine/runtime');
const VM = require('../../src/virtual-machine');
const mockRenderer = () => ({
setLayerGroupOrdering: () => {
// not relevant to this test
},
privateSkinAccess: true,
setPrivateSkinAccess (enabled) {
this.privateSkinAccess = enabled;
}
});
test('baseline: no external communication methods', t => {
const rt = new Runtime();
rt.attachRenderer(mockRenderer());
t.equal(rt.renderer.privateSkinAccess, true);
t.end();
});
test('throws errors for unknown method', t => {
t.plan(1);
const rt = new Runtime();
try {
rt.setExternalCommunicationMethod('something fake', true);
} catch (e) {
t.equal(e.message, 'Unknown method: something fake');
}
t.end();
});
test('communication method enabled after attaching renderer', t => {
const rt = new Runtime();
rt.attachRenderer(mockRenderer());
rt.setExternalCommunicationMethod('cloudVariables', true);
t.equal(rt.renderer.privateSkinAccess, false);
t.end();
});
test('communication method enabled before attaching renderer', t => {
const rt = new Runtime();
rt.setExternalCommunicationMethod('cloudVariables', true);
rt.attachRenderer(mockRenderer());
t.equal(rt.renderer.privateSkinAccess, false);
t.end();
});
test('disable enforcement', t => {
const rt = new Runtime();
rt.attachRenderer(mockRenderer());
rt.setEnforcePrivacy(false);
rt.setExternalCommunicationMethod('cloudVariables', true);
t.equal(rt.renderer.privateSkinAccess, true);
t.end();
});
test('multiple features toggled', t => {
const rt = new Runtime();
rt.attachRenderer(mockRenderer());
rt.setExternalCommunicationMethod('cloudVariables', true);
t.equal(rt.renderer.privateSkinAccess, false);
rt.setExternalCommunicationMethod('customExtensions', true);
t.equal(rt.renderer.privateSkinAccess, false);
rt.setExternalCommunicationMethod('cloudVariables', false);
t.equal(rt.renderer.privateSkinAccess, false);
rt.setExternalCommunicationMethod('customExtensions', false);
t.equal(rt.renderer.privateSkinAccess, true);
t.end();
});
test('cloud variables', t => {
const rt = new Runtime();
rt.attachRenderer(mockRenderer());
rt.addCloudVariable();
t.equal(rt.renderer.privateSkinAccess, false);
rt.addCloudVariable();
t.equal(rt.renderer.privateSkinAccess, false);
rt.removeCloudVariable();
t.equal(rt.renderer.privateSkinAccess, false);
rt.removeCloudVariable();
t.equal(rt.renderer.privateSkinAccess, true);
t.end();
});
test('custom extensions', async t => {
const vm = new VM();
vm.attachRenderer(mockRenderer());
vm.extensionManager.securityManager.getSandboxMode = () => 'unsandboxed';
global.document = {
createElement: () => {
const element = {};
setTimeout(() => {
global.Scratch.extensions.register({
getInfo: () => ({})
});
});
return element;
},
body: {
appendChild: () => {}
}
};
t.equal(vm.renderer.privateSkinAccess, true);
await vm.extensionManager.loadExtensionURL('data:application/javascript;,');
t.equal(vm.renderer.privateSkinAccess, false);
t.end();
});