@agoric/make-hardener
Advanced tools
Comparing version 0.0.6 to 0.0.7
@@ -68,125 +68,127 @@ 'use strict'; | ||
function harden(root) { | ||
const toFreeze = new Set(); | ||
const prototypes = new Map(); | ||
const paths = new WeakMap(); | ||
const { harden } = { | ||
harden(root) { | ||
const toFreeze = new Set(); | ||
const prototypes = new Map(); | ||
const paths = new WeakMap(); | ||
// If val is something we should be freezing but aren't yet, | ||
// add it to toFreeze. | ||
function enqueue(val, path) { | ||
if (Object(val) !== val) { | ||
// ignore primitives | ||
return; | ||
// If val is something we should be freezing but aren't yet, | ||
// add it to toFreeze. | ||
function enqueue(val, path) { | ||
if (Object(val) !== val) { | ||
// ignore primitives | ||
return; | ||
} | ||
const type = typeof val; | ||
if (type !== 'object' && type !== 'function') { | ||
// future proof: break until someone figures out what it should do | ||
throw new TypeError(`Unexpected typeof: ${type}`); | ||
} | ||
if (fringeSet.has(val) || toFreeze.has(val)) { | ||
// Ignore if this is an exit, or we've already visited it | ||
return; | ||
} | ||
// console.log(`adding ${val} to toFreeze`, val); | ||
toFreeze.add(val); | ||
paths.set(val, path); | ||
} | ||
const type = typeof val; | ||
if (type !== 'object' && type !== 'function') { | ||
// future proof: break until someone figures out what it should do | ||
throw new TypeError(`Unexpected typeof: ${type}`); | ||
} | ||
if (fringeSet.has(val) || toFreeze.has(val)) { | ||
// Ignore if this is an exit, or we've already visited it | ||
return; | ||
} | ||
// console.log(`adding ${val} to toFreeze`, val); | ||
toFreeze.add(val); | ||
paths.set(val, path); | ||
} | ||
function freezeAndTraverse(obj) { | ||
// Apply the naive preparer if they specified one. | ||
if (naivePrepareObject) { | ||
naivePrepareObject(obj); | ||
} | ||
function freezeAndTraverse(obj) { | ||
// Apply the naive preparer if they specified one. | ||
if (naivePrepareObject) { | ||
naivePrepareObject(obj); | ||
} | ||
// Now freeze the object to ensure reactive | ||
// objects such as proxies won't add properties | ||
// during traversal, before they get frozen. | ||
// Now freeze the object to ensure reactive | ||
// objects such as proxies won't add properties | ||
// during traversal, before they get frozen. | ||
// Object are verified before being enqueued, | ||
// therefore this is a valid candidate. | ||
// Throws if this fails (strict mode). | ||
freeze(obj); | ||
// Object are verified before being enqueued, | ||
// therefore this is a valid candidate. | ||
// Throws if this fails (strict mode). | ||
freeze(obj); | ||
// we rely upon certain commitments of Object.freeze and proxies here | ||
// we rely upon certain commitments of Object.freeze and proxies here | ||
// get stable/immutable outbound links before a Proxy has a chance to do | ||
// something sneaky. | ||
const proto = getPrototypeOf(obj); | ||
const descs = getOwnPropertyDescriptors(obj); | ||
const path = paths.get(obj) || 'unknown'; | ||
// get stable/immutable outbound links before a Proxy has a chance to do | ||
// something sneaky. | ||
const proto = getPrototypeOf(obj); | ||
const descs = getOwnPropertyDescriptors(obj); | ||
const path = paths.get(obj) || 'unknown'; | ||
// console.log(`adding ${proto} to prototypes under ${path}`); | ||
if (proto !== null && !prototypes.has(proto)) { | ||
prototypes.set(proto, path); | ||
paths.set(proto, `${path}.__proto__`); | ||
} | ||
// console.log(`adding ${proto} to prototypes under ${path}`); | ||
if (proto !== null && !prototypes.has(proto)) { | ||
prototypes.set(proto, path); | ||
paths.set(proto, `${path}.__proto__`); | ||
} | ||
ownKeys(descs).forEach(name => { | ||
const pathname = `${path}.${String(name)}`; | ||
// todo uncurried form | ||
// todo: getOwnPropertyDescriptors is guaranteed to return well-formed | ||
// descriptors, but they still inherit from Object.prototype. If | ||
// someone has poisoned Object.prototype to add 'value' or 'get' | ||
// properties, then a simple 'if ("value" in desc)' or 'desc.value' | ||
// test could be confused. We use hasOwnProperty to be sure about | ||
// whether 'value' is present or not, which tells us for sure that this | ||
// is a data property. | ||
const desc = descs[name]; | ||
if ('value' in desc) { | ||
ownKeys(descs).forEach(name => { | ||
const pathname = `${path}.${String(name)}`; | ||
// todo uncurried form | ||
enqueue(desc.value, `${pathname}`); | ||
} else { | ||
enqueue(desc.get, `${pathname}(get)`); | ||
enqueue(desc.set, `${pathname}(set)`); | ||
} | ||
}); | ||
} | ||
// todo: getOwnPropertyDescriptors is guaranteed to return well-formed | ||
// descriptors, but they still inherit from Object.prototype. If | ||
// someone has poisoned Object.prototype to add 'value' or 'get' | ||
// properties, then a simple 'if ("value" in desc)' or 'desc.value' | ||
// test could be confused. We use hasOwnProperty to be sure about | ||
// whether 'value' is present or not, which tells us for sure that this | ||
// is a data property. | ||
const desc = descs[name]; | ||
if ('value' in desc) { | ||
// todo uncurried form | ||
enqueue(desc.value, `${pathname}`); | ||
} else { | ||
enqueue(desc.get, `${pathname}(get)`); | ||
enqueue(desc.set, `${pathname}(set)`); | ||
} | ||
}); | ||
} | ||
function dequeue() { | ||
// New values added before forEach() has finished will be visited. | ||
toFreeze.forEach(freezeAndTraverse); // todo curried forEach | ||
} | ||
function dequeue() { | ||
// New values added before forEach() has finished will be visited. | ||
toFreeze.forEach(freezeAndTraverse); // todo curried forEach | ||
} | ||
function checkPrototypes() { | ||
prototypes.forEach((path, p) => { | ||
if (!(toFreeze.has(p) || fringeSet.has(p))) { | ||
// all reachable properties have already been frozen by this point | ||
let msg; | ||
try { | ||
msg = `prototype ${p} of ${path} is not already in the fringeSet`; | ||
} catch (e) { | ||
// `${(async _=>_).__proto__}` fails in most engines | ||
msg = | ||
'a prototype of something is not already in the fringeset (and .toString failed)'; | ||
function checkPrototypes() { | ||
prototypes.forEach((path, p) => { | ||
if (!(toFreeze.has(p) || fringeSet.has(p))) { | ||
// all reachable properties have already been frozen by this point | ||
let msg; | ||
try { | ||
console.log(msg); | ||
console.log('the prototype:', p); | ||
console.log('of something:', path); | ||
} catch (_e) { | ||
// console.log might be missing in restrictive SES realms | ||
msg = `prototype ${p} of ${path} is not already in the fringeSet`; | ||
} catch (e) { | ||
// `${(async _=>_).__proto__}` fails in most engines | ||
msg = | ||
'a prototype of something is not already in the fringeset (and .toString failed)'; | ||
try { | ||
console.log(msg); | ||
console.log('the prototype:', p); | ||
console.log('of something:', path); | ||
} catch (_e) { | ||
// console.log might be missing in restrictive SES realms | ||
} | ||
} | ||
throw new TypeError(msg); | ||
} | ||
throw new TypeError(msg); | ||
} | ||
}); | ||
} | ||
}); | ||
} | ||
function commit() { | ||
// todo curried forEach | ||
// we capture the real WeakSet.prototype.add above, in case someone | ||
// changes it. The two-argument form of forEach passes the second | ||
// argument as the 'this' binding, so we add to the correct set. | ||
toFreeze.forEach(fringeSet.add, fringeSet); | ||
} | ||
function commit() { | ||
// todo curried forEach | ||
// we capture the real WeakSet.prototype.add above, in case someone | ||
// changes it. The two-argument form of forEach passes the second | ||
// argument as the 'this' binding, so we add to the correct set. | ||
toFreeze.forEach(fringeSet.add, fringeSet); | ||
} | ||
enqueue(root); | ||
dequeue(); | ||
// console.log("fringeSet", fringeSet); | ||
// console.log("prototype set:", prototypes); | ||
// console.log("toFreeze set:", toFreeze); | ||
checkPrototypes(); | ||
commit(); | ||
enqueue(root); | ||
dequeue(); | ||
// console.log("fringeSet", fringeSet); | ||
// console.log("prototype set:", prototypes); | ||
// console.log("toFreeze set:", toFreeze); | ||
checkPrototypes(); | ||
commit(); | ||
return root; | ||
} | ||
return root; | ||
}, | ||
}; | ||
@@ -193,0 +195,0 @@ return harden; |
@@ -5,3 +5,3 @@ (function (global, factory) { | ||
(global = global || self, global.makeHardener = factory()); | ||
}(this, function () { 'use strict'; | ||
}(this, (function () { 'use strict'; | ||
@@ -73,125 +73,127 @@ // Adapted from SES/Caja - Copyright (C) 2011 Google Inc. | ||
function harden(root) { | ||
const toFreeze = new Set(); | ||
const prototypes = new Map(); | ||
const paths = new WeakMap(); | ||
const { harden } = { | ||
harden(root) { | ||
const toFreeze = new Set(); | ||
const prototypes = new Map(); | ||
const paths = new WeakMap(); | ||
// If val is something we should be freezing but aren't yet, | ||
// add it to toFreeze. | ||
function enqueue(val, path) { | ||
if (Object(val) !== val) { | ||
// ignore primitives | ||
return; | ||
// If val is something we should be freezing but aren't yet, | ||
// add it to toFreeze. | ||
function enqueue(val, path) { | ||
if (Object(val) !== val) { | ||
// ignore primitives | ||
return; | ||
} | ||
const type = typeof val; | ||
if (type !== 'object' && type !== 'function') { | ||
// future proof: break until someone figures out what it should do | ||
throw new TypeError(`Unexpected typeof: ${type}`); | ||
} | ||
if (fringeSet.has(val) || toFreeze.has(val)) { | ||
// Ignore if this is an exit, or we've already visited it | ||
return; | ||
} | ||
// console.log(`adding ${val} to toFreeze`, val); | ||
toFreeze.add(val); | ||
paths.set(val, path); | ||
} | ||
const type = typeof val; | ||
if (type !== 'object' && type !== 'function') { | ||
// future proof: break until someone figures out what it should do | ||
throw new TypeError(`Unexpected typeof: ${type}`); | ||
} | ||
if (fringeSet.has(val) || toFreeze.has(val)) { | ||
// Ignore if this is an exit, or we've already visited it | ||
return; | ||
} | ||
// console.log(`adding ${val} to toFreeze`, val); | ||
toFreeze.add(val); | ||
paths.set(val, path); | ||
} | ||
function freezeAndTraverse(obj) { | ||
// Apply the naive preparer if they specified one. | ||
if (naivePrepareObject) { | ||
naivePrepareObject(obj); | ||
} | ||
function freezeAndTraverse(obj) { | ||
// Apply the naive preparer if they specified one. | ||
if (naivePrepareObject) { | ||
naivePrepareObject(obj); | ||
} | ||
// Now freeze the object to ensure reactive | ||
// objects such as proxies won't add properties | ||
// during traversal, before they get frozen. | ||
// Now freeze the object to ensure reactive | ||
// objects such as proxies won't add properties | ||
// during traversal, before they get frozen. | ||
// Object are verified before being enqueued, | ||
// therefore this is a valid candidate. | ||
// Throws if this fails (strict mode). | ||
freeze(obj); | ||
// Object are verified before being enqueued, | ||
// therefore this is a valid candidate. | ||
// Throws if this fails (strict mode). | ||
freeze(obj); | ||
// we rely upon certain commitments of Object.freeze and proxies here | ||
// we rely upon certain commitments of Object.freeze and proxies here | ||
// get stable/immutable outbound links before a Proxy has a chance to do | ||
// something sneaky. | ||
const proto = getPrototypeOf(obj); | ||
const descs = getOwnPropertyDescriptors(obj); | ||
const path = paths.get(obj) || 'unknown'; | ||
// get stable/immutable outbound links before a Proxy has a chance to do | ||
// something sneaky. | ||
const proto = getPrototypeOf(obj); | ||
const descs = getOwnPropertyDescriptors(obj); | ||
const path = paths.get(obj) || 'unknown'; | ||
// console.log(`adding ${proto} to prototypes under ${path}`); | ||
if (proto !== null && !prototypes.has(proto)) { | ||
prototypes.set(proto, path); | ||
paths.set(proto, `${path}.__proto__`); | ||
} | ||
// console.log(`adding ${proto} to prototypes under ${path}`); | ||
if (proto !== null && !prototypes.has(proto)) { | ||
prototypes.set(proto, path); | ||
paths.set(proto, `${path}.__proto__`); | ||
} | ||
ownKeys(descs).forEach(name => { | ||
const pathname = `${path}.${String(name)}`; | ||
// todo uncurried form | ||
// todo: getOwnPropertyDescriptors is guaranteed to return well-formed | ||
// descriptors, but they still inherit from Object.prototype. If | ||
// someone has poisoned Object.prototype to add 'value' or 'get' | ||
// properties, then a simple 'if ("value" in desc)' or 'desc.value' | ||
// test could be confused. We use hasOwnProperty to be sure about | ||
// whether 'value' is present or not, which tells us for sure that this | ||
// is a data property. | ||
const desc = descs[name]; | ||
if ('value' in desc) { | ||
ownKeys(descs).forEach(name => { | ||
const pathname = `${path}.${String(name)}`; | ||
// todo uncurried form | ||
enqueue(desc.value, `${pathname}`); | ||
} else { | ||
enqueue(desc.get, `${pathname}(get)`); | ||
enqueue(desc.set, `${pathname}(set)`); | ||
} | ||
}); | ||
} | ||
// todo: getOwnPropertyDescriptors is guaranteed to return well-formed | ||
// descriptors, but they still inherit from Object.prototype. If | ||
// someone has poisoned Object.prototype to add 'value' or 'get' | ||
// properties, then a simple 'if ("value" in desc)' or 'desc.value' | ||
// test could be confused. We use hasOwnProperty to be sure about | ||
// whether 'value' is present or not, which tells us for sure that this | ||
// is a data property. | ||
const desc = descs[name]; | ||
if ('value' in desc) { | ||
// todo uncurried form | ||
enqueue(desc.value, `${pathname}`); | ||
} else { | ||
enqueue(desc.get, `${pathname}(get)`); | ||
enqueue(desc.set, `${pathname}(set)`); | ||
} | ||
}); | ||
} | ||
function dequeue() { | ||
// New values added before forEach() has finished will be visited. | ||
toFreeze.forEach(freezeAndTraverse); // todo curried forEach | ||
} | ||
function dequeue() { | ||
// New values added before forEach() has finished will be visited. | ||
toFreeze.forEach(freezeAndTraverse); // todo curried forEach | ||
} | ||
function checkPrototypes() { | ||
prototypes.forEach((path, p) => { | ||
if (!(toFreeze.has(p) || fringeSet.has(p))) { | ||
// all reachable properties have already been frozen by this point | ||
let msg; | ||
try { | ||
msg = `prototype ${p} of ${path} is not already in the fringeSet`; | ||
} catch (e) { | ||
// `${(async _=>_).__proto__}` fails in most engines | ||
msg = | ||
'a prototype of something is not already in the fringeset (and .toString failed)'; | ||
function checkPrototypes() { | ||
prototypes.forEach((path, p) => { | ||
if (!(toFreeze.has(p) || fringeSet.has(p))) { | ||
// all reachable properties have already been frozen by this point | ||
let msg; | ||
try { | ||
console.log(msg); | ||
console.log('the prototype:', p); | ||
console.log('of something:', path); | ||
} catch (_e) { | ||
// console.log might be missing in restrictive SES realms | ||
msg = `prototype ${p} of ${path} is not already in the fringeSet`; | ||
} catch (e) { | ||
// `${(async _=>_).__proto__}` fails in most engines | ||
msg = | ||
'a prototype of something is not already in the fringeset (and .toString failed)'; | ||
try { | ||
console.log(msg); | ||
console.log('the prototype:', p); | ||
console.log('of something:', path); | ||
} catch (_e) { | ||
// console.log might be missing in restrictive SES realms | ||
} | ||
} | ||
throw new TypeError(msg); | ||
} | ||
throw new TypeError(msg); | ||
} | ||
}); | ||
} | ||
}); | ||
} | ||
function commit() { | ||
// todo curried forEach | ||
// we capture the real WeakSet.prototype.add above, in case someone | ||
// changes it. The two-argument form of forEach passes the second | ||
// argument as the 'this' binding, so we add to the correct set. | ||
toFreeze.forEach(fringeSet.add, fringeSet); | ||
} | ||
function commit() { | ||
// todo curried forEach | ||
// we capture the real WeakSet.prototype.add above, in case someone | ||
// changes it. The two-argument form of forEach passes the second | ||
// argument as the 'this' binding, so we add to the correct set. | ||
toFreeze.forEach(fringeSet.add, fringeSet); | ||
} | ||
enqueue(root); | ||
dequeue(); | ||
// console.log("fringeSet", fringeSet); | ||
// console.log("prototype set:", prototypes); | ||
// console.log("toFreeze set:", toFreeze); | ||
checkPrototypes(); | ||
commit(); | ||
enqueue(root); | ||
dequeue(); | ||
// console.log("fringeSet", fringeSet); | ||
// console.log("prototype set:", prototypes); | ||
// console.log("toFreeze set:", toFreeze); | ||
checkPrototypes(); | ||
commit(); | ||
return root; | ||
} | ||
return root; | ||
}, | ||
}; | ||
@@ -203,2 +205,2 @@ return harden; | ||
})); | ||
}))); |
{ | ||
"name": "@agoric/make-hardener", | ||
"version": "0.0.6", | ||
"version": "0.0.7", | ||
"description": "Create a 'hardener' which freezes the API surface of a set of objects", | ||
"main": "dist/make-hardener.cjs.js", | ||
"module": "dist/make-hardener.esm.js", | ||
"browser": "dist/make-hardener.umd.js", | ||
"scripts": { | ||
"test": "node -r esm test/test.js", | ||
"build": "rollup -c", | ||
"lint-fix": "eslint --fix '**/*.{js,jsx}'", | ||
"lint-check": "eslint '**/*.{js,jsx}'" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/Agoric/make-hardener.git" | ||
}, | ||
"author": "Agoric", | ||
"license": "Apache-2.0", | ||
"bugs": { | ||
"url": "https://github.com/Agoric/make-hardener/issues" | ||
}, | ||
"homepage": "https://github.com/Agoric/make-hardener#readme", | ||
"dependencies": {}, | ||
"devDependencies": { | ||
"eslint": "^5.3.0", | ||
"eslint-config-airbnb": "^17.1.0", | ||
"eslint-config-prettier": "^4.0.0", | ||
"eslint-plugin-import": "^2.16.0", | ||
"eslint-plugin-jsx-a11y": "^6.2.1", | ||
"eslint-plugin-prettier": "^3.0.1", | ||
"eslint-plugin-react": "^7.12.4", | ||
"esm": "^3.2.7", | ||
"prettier": "1.16.4", | ||
"rollup": "^1.2.2", | ||
"tape": "^4.9.2" | ||
}, | ||
"directories": { | ||
"test": "test" | ||
}, | ||
"keywords": [ | ||
@@ -47,5 +13,39 @@ "deepFreeze", | ||
], | ||
"homepage": "https://github.com/Agoric/packages/make-hardener#readme", | ||
"bugs": { | ||
"url": "https://github.com/Agoric/make-hardener/issues" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/Agoric/ses-shim.git" | ||
}, | ||
"files": [ | ||
"dist" | ||
] | ||
], | ||
"directories": { | ||
"test": "test" | ||
}, | ||
"type": "module", | ||
"main": "./src/main.js", | ||
"browser": "dist/make-hardener.umd.js", | ||
"scripts": { | ||
"depcheck": "depcheck", | ||
"lint": "eslint '**/*.js'", | ||
"lint-fix": "eslint --fix '**/*.js'", | ||
"test": "tap --no-esm --no-coverage --reporter spec 'test/**/*.test.js'", | ||
"build": "rollup -c rollup.config.js" | ||
}, | ||
"devDependencies": { | ||
"babel-eslint": "^10.0.3", | ||
"eslint": "^6.8.0", | ||
"eslint-config-airbnb-base": "^14.0.0", | ||
"eslint-config-prettier": "^6.9.0", | ||
"eslint-plugin-eslint-comments": "^3.1.2", | ||
"eslint-plugin-import": "^2.19.1", | ||
"eslint-plugin-prettier": "^3.1.2", | ||
"prettier": "^1.19.1", | ||
"rollup": "1.31.0", | ||
"rollup-plugin-node-resolve": "5.2.0", | ||
"tap": "14.10.5" | ||
} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Yes
29060
5
351
2
1