Skip to content

Commit

Permalink
Harden Snowboard (#687)
Browse files Browse the repository at this point in the history
Backport from 1.2 branch.

- The Snowboard and PluginLoader objects are now frozen and cannot be modified.
- Added a Proxy in front of Snowboard to handle plugin loading
- Plugin "Snowboard" instances are blocked from running certain methods
- Update tests to check hardening
  • Loading branch information
bennothommo committed Sep 16, 2022
1 parent 107e1d0 commit bce4b59
Show file tree
Hide file tree
Showing 20 changed files with 395 additions and 52 deletions.
6 changes: 5 additions & 1 deletion modules/system/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,9 @@
"math": "always"
}],
"vue/multi-word-component-names": ["off"]
}
},
"ignorePatterns": [
"tests/js",
"**/build/*.js"
]
}
2 changes: 1 addition & 1 deletion modules/system/assets/js/build/manifest.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion modules/system/assets/js/build/system.js

Large diffs are not rendered by default.

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion modules/system/assets/js/snowboard/build/snowboard.base.js

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

43 changes: 43 additions & 0 deletions modules/system/assets/js/snowboard/main/InnerProxyHandler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* Internal proxy for Snowboard.
*
* This handler wraps the Snowboard instance that is passed to the constructor of plugin instances.
* It prevents access to the following methods:
* - `attachAbstracts`: No need to attach abstracts again.
* - `loadUtilties`: No need to load utilities again.
* - `initialise`: Snowboard is already initialised.
* - `initialiseSingletons`: Singletons are already initialised.
*/
export default {
get(target, prop, receiver) {
if (typeof prop === 'string') {
const propLower = prop.toLowerCase();

if (['attachAbstracts', 'loadUtilities', 'initialise', 'initialiseSingletons'].includes(prop)) {
throw new Error(`You cannot use the "${prop}" Snowboard method within a plugin.`);
}

if (target.hasPlugin(propLower)) {
return (...params) => Reflect.get(target, 'plugins')[propLower].getInstance(...params);
}
}

return Reflect.get(target, prop, receiver);
},

has(target, prop) {
if (typeof prop === 'string') {
const propLower = prop.toLowerCase();

if (['attachAbstracts', 'loadUtilities', 'initialise', 'initialiseSingletons'].includes(prop)) {
return false;
}

if (target.hasPlugin(propLower)) {
return true;
}
}

return Reflect.has(target, prop);
},
};
30 changes: 25 additions & 5 deletions modules/system/assets/js/snowboard/main/PluginLoader.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import PluginBase from '../abstracts/PluginBase';
import Singleton from '../abstracts/Singleton';
import InnerProxyHandler from './InnerProxyHandler';

/**
* Plugin loader class.
Expand All @@ -22,13 +23,28 @@ export default class PluginLoader {
*/
constructor(name, snowboard, instance) {
this.name = name;
this.snowboard = snowboard;
this.snowboard = new Proxy(
snowboard,
InnerProxyHandler,
);
this.instance = instance;

// Freeze instance that has been inserted into this loader
Object.freeze(this.instance);

this.instances = [];
this.singleton = instance.prototype instanceof Singleton;
this.initialised = instance.prototype instanceof PluginBase;
this.singleton = {
initialised: false,
};
// Prevent further extension of the singleton status object
Object.seal(this.singleton);

this.mocks = {};
this.originalFunctions = {};

// Freeze loader itself
Object.freeze(PluginLoader.prototype);
Object.freeze(this);
}

/**
Expand Down Expand Up @@ -162,7 +178,11 @@ export default class PluginLoader {
* @returns {boolean}
*/
isInitialised() {
return this.initialised;
if (!this.isSingleton()) {
return true;
}

return this.singleton.initialised;
}

/**
Expand All @@ -179,7 +199,7 @@ export default class PluginLoader {
newInstance.detach = () => this.instances.splice(this.instances.indexOf(newInstance), 1);
newInstance.construct(...parameters);
this.instances.push(newInstance);
this.initialised = true;
this.singleton.initialised = true;
}

/**
Expand Down
25 changes: 25 additions & 0 deletions modules/system/assets/js/snowboard/main/ProxyHandler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export default {
get(target, prop, receiver) {
if (typeof prop === 'string') {
const propLower = prop.toLowerCase();

if (target.hasPlugin(propLower)) {
return (...params) => Reflect.get(target, 'plugins')[propLower].getInstance(...params);
}
}

return Reflect.get(target, prop, receiver);
},

has(target, prop) {
if (typeof prop === 'string') {
const propLower = prop.toLowerCase();

if (target.hasPlugin(propLower)) {
return true;
}
}

return Reflect.has(target, prop);
},
};
Loading

0 comments on commit bce4b59

Please sign in to comment.