ProctorJS

ProctorJS helps you cover your assests

Interactive Lab

Below is a fully interactive lab where you can experiment with the features of ProctorJS. The top window represents the third-party component, distributed as a closure. The second code window represents the website hosting the code.

There are some limitations with the code windows to be aware of, you will need to use strict JavaScript semicolon placement after every command and function declaration and launch the browser dev tools to view the output in the console.

(a,b,c)=>{
    console.assert([a,b,c].join() == "a,b,c", '%s != a,b,c', [a,b,c].join());
    console.assert(this.demo != undefined, '%s is undefined', 'demo');
    console.assert(window != undefined, '%s is undefined', 'window');
    console.assert(window.location != undefined, '%s is undefined', 'window.location');
    console.assert(window.document == undefined, '%s is NOT undefined', 'window.document');
    console.assert(window.location.href != undefined, '%s is undefined', 'window.location.href');
    return (() =>{
        this.test =()=>{
        console.assert(this.demo != undefined, '%s is undefined', 'demo');
        console.assert(window != undefined, '%s is undefined', 'window');
        console.assert(window.location != undefined, '%s is undefined', 'window.location');
        console.assert(window.location.href != undefined, '%s is undefined', 'window.location.href');
        console.assert(Array != undefined, '%s is undefined', 'Array');
        window.location.href = "/404";
        this.demo();
        };
        return this;
    })();
}
                

console.assert(proctor != undefined, '%s is undefined', 'proctor');
console.log(proctor.version);
/*******************************************************************************
Protect a sensitive global variables
*******************************************************************************/
proctor.protect("Array");

/*******************************************************************************
Create a custom policy to manage access to a sensitive global variable
*******************************************************************************/
custom_policy = function (id) {
    let p = proctor.policies.default();
    p.id = id.replace("//","").replace("/",":");
    p.type = "debug",
    p.on_get = function(target, property) {
        result = ["location","href","test", "demo"].includes(property);
        console.log(`%cPolicy:${this.id},${result?"Allow":"Deny"}:get:`,`color:white;background-color:${result?"green":"red"}`, property);
        return result;
    };
    p.on_set = function(target, property, value) {
        result =  ["name","test"].includes(property);
        console.log(`%cPolicy:${this.id},${result?"Allow":"Deny"}:set:`,`color:white;background-color:${result?"green":"red"}`, target, property, value);
        return result;
    };
    p.on_invoke = function(target, property, args) {
        result = true;
        console.log(`%cPolicy:${this.id},${result?"Allow":"Deny"}:invoke:`,`color:white;background-color:${result?"green":"red"}`, target, property);
        return result;
    };
    return p;
};

/*******************************************************************************
Create a custom context for the plugin to use
*******************************************************************************/
context = {
    demo : ()=>{
        return 'Hello World';
    }
};

/*******************************************************************************
Anonymize the methods
*******************************************************************************/
console.log(`before:${context.demo}`);
context.demo = proctor.anonymize(context.demo);
console.log(`after:${context.demo}`);


/*******************************************************************************
Make sure plugins can't tamper with your custom context
*******************************************************************************/
protected = custom_policy("context").defend(context);


/*******************************************************************************
Create a filter to allow access to the window global variable.
But don't worry based on your custom_policy all they will have is read-only
access to the window.location.href property.
*******************************************************************************/
filter = (global)=>!["window","Array"].includes(global);

/*******************************************************************************
Now proctor the plugin 
*******************************************************************************/
console.log(`URL:${plugin.url}`);

proctor
.load(plugin.url, ["a","b","c"], protected, filter, ()=> custom_policy)
.then(v1=>{
    v1.test();
});
                
Execute Code

ProctorJS provides a policy-based isolation framework into which you can load third-party components and plugins. These components are loaded into their own scopes without access to global variables, except those which you explicitly allow.

You can provide access to global variables and objects with exclusion filters or create custom contexts through which components can interact with your content. You can also use custom policies to manage which methods and properties code can access.