aran-access-control
Version:
Access Control System for Aran
216 lines (201 loc) • 10.5 kB
JavaScript
const CreateForeignTameObject = require("./create-foreign-tame-object.js");
const CreateForeignWildObject = require("./create-foreign-wild-object.js");
const NormalizedArray = require("./normalized-array.js");
const Region = require("./region.js");
const Error = global.Error;
const String = global.String;
const eval = global.eval;
const Object_create = Object.create;
const Object_prototype = Object.prototype;
const Function_prototype = Function.prototype;
const Array_prototype = Array.prototype;
const Symbol_iterator = Symbol.iterator;
const Reflect_apply = Reflect.apply;
const Reflect_construct = Reflect.construct;
const Reflect_defineProperty = Reflect.defineProperty;
const Reflect_deleteProperty = Reflect.deleteProperty;
const Reflect_get = Reflect.get;
const Reflect_getOwnPropertyDescriptor = Reflect.getOwnPropertyDescriptor;
const Reflect_getPrototypeOf = Reflect.getPrototypeOf;
const Reflect_has = Reflect.has;
const Reflect_isExtensible = Reflect.isExtensible;
const Reflect_preventExtensions = Reflect.preventExtensions;
const Reflect_ownKeys = Reflect.ownKeys;
const Reflect_set = Reflect.set;
const Reflect_setPrototypeOf = Reflect.setPrototypeOf;
module.exports = (membrane) => {
const access = ((() => {
const tame = Region();
const wild = Region();
tame.resolve_native_external_objects(wild.native_internal_objects);
wild.resolve_native_external_objects(tame.native_internal_objects);
create_foreign_tame_object = CreateForeignTameObject(membrane, wild.internal_value_of, tame.internal_value_of);
create_foreign_wild_object = CreateForeignWildObject(membrane, tame.internal_value_of, wild.internal_value_of);
tame.resolve_create_foreign_internal_object(create_foreign_tame_object);
wild.resolve_create_foreign_internal_object(create_foreign_wild_object);
return {capture:tame.internal_value_of, release:wild.internal_value_of};
}) ());
const capture = access.capture;
const release = access.release;
const narray = NormalizedArray(membrane, capture, release);
const advice = {SANDBOX:capture(global)};
///////////////
// Producers //
///////////////
advice.arrival = (strict, _scope, serial) => {
const _arguments = _scope.arguments;
_scope.arguments.length = membrane.enter(_scope.arguments.length);
_scope.arguments[Symbol_iterator] = membrane.enter(capture(_scope.arguments[Symbol_iterator]));
if (!strict)
_scope.arguments.callee = membrane.enter(_scope.callee);
Reflect_setPrototypeOf(_scope.arguments, capture(Object_prototype));
return {
new: membrane.enter(_scope.new),
callee: membrane.enter(_scope.callee),
this: membrane.enter(_scope.this),
arguments: membrane.enter(_scope.arguments)
};
};
advice.begin = (strict, scope, serial) => {
if (scope) {
for (var key in scope) {
scope[key] = membrane.enter(capture(key));
}
}
return scope;
}
advice.catch = (value, serial) => membrane.enter(capture(value));
advice.primitive = (value, serial) => membrane.enter(value);
advice.discard = (identifier, value, serial) => membrane.enter(value);
advice.regexp = (value, serial) => membrane.enter(capture(value));
advice.closure = (_value, serial) => {
Reflect_defineProperty(_value, "length", {
value: membrane.enter(_value.length),
writable: false,
enumerable: false,
configurable: true
});
Reflect_defineProperty(_value, "name", {
value: membrane.enter(_value.name),
writable: false,
enumerable: false,
configurable: true
});
Reflect_setPrototypeOf(_value, capture(Function_prototype));
if (!("prototype" in _value))
return membrane.enter(value);
const $prototype = Object_create(capture(Object_prototype))
const $$value = membrane.enter(_value);
Reflect_defineProperty($prototype, "constructor", {
value: $$value,
writable: true,
enumerable: false,
configurable: true
});
_value.prototype = membrane.enter($prototype);
return $$value;
};
///////////////
// Consumers //
///////////////
advice.return = ($scope, $$value, serial) => {
if (membrane.leave($scope.new)) {
const $value = membrane.leave($$value);
if (!$value || (typeof $value !== "object" && typeof $value !== "function"))
return $scope.this;
}
return $$value;
};
advice.throw = ($$value, serial) => release(membrane.leave($$value));
advice.success = ($scope, $$value, serial) => $scope ? release(membrane.leave($$value)) : $$value;
advice.test = ($$value, serial) => membrane.leave($$value);
advice.eval = ($$value, serial) => membrane.instrument(String(release(membrane.leave($$value))), serial);
advice.with = ($$value, serial) => membrane.leave($$value);
///////////////
// Combiners //
///////////////
advice.apply = ($$value, array$$value, serial) => {
switch (array$$value.length) {
case 0: return membrane.leave($$value)();
case 1: return membrane.leave($$value)(array$$value[0]);
case 2: return membrane.leave($$value)(array$$value[0], array$$value[1]);
case 3: return membrane.leave($$value)(array$$value[0], array$$value[1], array$$value[2]);
}
return Reflect_apply(membrane.leave($$value), void 0, array$$value);
};
advice.invoke = ($$value1, $$value2, array$$value, serial) => {
const $value1 = membrane.leave($$value1);
return Reflect_apply(membrane.leave($value1[release(membrane.leave($$value2))]), $value1, array$$value);
};
advice.construct = ($$value, array$$value, serial) => {
switch (array$$value.length) {
case 0: return new (membrane.leave($$value))();
case 1: return new (membrane.leave($$value))(array$$value[0]);
case 2: return new (membrane.leave($$value))(array$$value[0], array$$value[1]);
case 3: return new (membrane.leave($$value))(array$$value[0], array$$value[1], array$$value[2]);
}
return Reflect_construct(membrane.leave($$value), array$$value);
};
advice.get = ($$value1, $$value2, serial) => {
const $value1 = membrane.leave($$value1);
const value2 = release(membrane.leave($$value2));
if ($value1 && (typeof $value1 === "object" || typeof $value1 === "function"))
return $value1[value2];
return membrane.enter($value1[value2]);
}
advice.set = ($$value1, $$value2, $$value3, serial) => membrane.leave($$value1)[release(membrane.leave($$value2))] = $$value3;
advice.delete = ($$value1, $$value2) => membrane.enter(delete membrane.leave($$value1)[release(membrane.leave($$value2))]);
advice.array = (array$$value, serial) => {
const $$value = [];
Reflect_setPrototypeOf($$value, capture(Array_prototype));
for (let index=0, length=array$$value.length; index < length; index++)
$$value[index] = array$$value[index];
return membrane.enter(narray($$value));
};
advice.object = (_properties, serial) => {
const value = Object_create(capture(Object_prototype));
for (let index=0, length = _properties.length; index < length; index++)
value[release(membrane.leave(_properties[index][0]))] = _properties[index][1];
return membrane.enter(value);
};
advice.unary = (operator, $$value, serial) => {
switch (operator) {
case "-": return membrane.enter(- release(membrane.leave($$value)));
case "+": return membrane.enter(+ release(membrane.leave($$value)));
case "!": return membrane.enter(! release(membrane.leave($$value)));
case "~": return membrane.enter(~ release(membrane.leave($$value)));
case "typeof": return membrane.enter(typeof release(membrane.leave($$value)));
case "void": return membrane.enter(void release(membrane.leave($$value)));
}
throw new Error("Unknown unary operator: "+operator);
};
advice.binary = (operator, $$value1, $$value2, serial) => {
switch (operator) {
case "==": return membrane.enter(release(membrane.leave($$value1)) == release(membrane.leave($$value2)));
case "!=": return membrane.enter(release(membrane.leave($$value1)) != release(membrane.leave($$value2)));
case "===": return membrane.enter(release(membrane.leave($$value1)) === release(membrane.leave($$value2)));
case "!==": return membrane.enter(release(membrane.leave($$value1)) !== release(membrane.leave($$value2)));
case "<": return membrane.enter(release(membrane.leave($$value1)) < release(membrane.leave($$value2)));
case "<=": return membrane.enter(release(membrane.leave($$value1)) <= release(membrane.leave($$value2)));
case ">": return membrane.enter(release(membrane.leave($$value1)) > release(membrane.leave($$value2)));
case ">=": return membrane.enter(release(membrane.leave($$value1)) >= release(membrane.leave($$value2)));
case "<<": return membrane.enter(release(membrane.leave($$value1)) << release(membrane.leave($$value2)));
case ">>": return membrane.enter(release(membrane.leave($$value1)) >> release(membrane.leave($$value2)));
case ">>>": return membrane.enter(release(membrane.leave($$value1)) >>> release(membrane.leave($$value2)));
case "+": return membrane.enter(release(membrane.leave($$value1)) + release(membrane.leave($$value2)));
case "-": return membrane.enter(release(membrane.leave($$value1)) - release(membrane.leave($$value2)));
case "*": return membrane.enter(release(membrane.leave($$value1)) * release(membrane.leave($$value2)));
case "/": return membrane.enter(release(membrane.leave($$value1)) / release(membrane.leave($$value2)));
case "%": return membrane.enter(release(membrane.leave($$value1)) % release(membrane.leave($$value2)));
case "|": return membrane.enter(release(membrane.leave($$value1)) | release(membrane.leave($$value2)));
case "^": return membrane.enter(release(membrane.leave($$value1)) ^ release(membrane.leave($$value2)));
case "&": return membrane.enter(release(membrane.leave($$value1)) & release(membrane.leave($$value2)));
case "in": return membrane.enter(release(membrane.leave($$value1)) in release(membrane.leave($$value2)));
case "instanceof": return membrane.enter(release(membrane.leave($$value1)) instanceof release(membrane.leave($$value2)));
}
throw new Error("Unknown binary operator: "+operator);
};
access.advice = advice;
access.membrane = membrane;
return access;
};