Merge branch '4.x'
# Conflicts: # components/bower.json # components/handlebars.js.nuspec # components/package.json # package.json
- Loading branch information
- +1 −1 Gruntfile.js
- +9 −1 lib/handlebars/base.js
- 0 lib/handlebars/internal/{createNewLookupObject.js → create-new-lookup-object.js}
- +70 −0 lib/handlebars/internal/proto-access.js
- +5 −0 lib/handlebars/internal/wrapHelper.js
- +13 −16 lib/handlebars/runtime.js
- +45 −1 release-notes.md
- +9 −0 spec/regressions.js
- +191 −95 spec/security.js
- +4 −2 types/index.d.ts
- +4 −2 types/test.ts
| @@ -0,0 +1,70 @@ | ||
| import { createNewLookupObject } from './create-new-lookup-object'; | ||
| import * as logger from '../logger'; | ||
|
|
||
| const loggedProperties = Object.create(null); | ||
|
|
||
| export function createProtoAccessControl(runtimeOptions) { | ||
| let defaultMethodWhiteList = Object.create(null); | ||
| defaultMethodWhiteList['constructor'] = false; | ||
| defaultMethodWhiteList['__defineGetter__'] = false; | ||
| defaultMethodWhiteList['__defineSetter__'] = false; | ||
| defaultMethodWhiteList['__lookupGetter__'] = false; | ||
|
|
||
| let defaultPropertyWhiteList = Object.create(null); | ||
| // eslint-disable-next-line no-proto | ||
| defaultPropertyWhiteList['__proto__'] = false; | ||
|
|
||
| return { | ||
| properties: { | ||
| whitelist: createNewLookupObject( | ||
| defaultPropertyWhiteList, | ||
| runtimeOptions.allowedProtoProperties | ||
| ), | ||
| defaultValue: runtimeOptions.allowProtoPropertiesByDefault | ||
| }, | ||
| methods: { | ||
| whitelist: createNewLookupObject( | ||
| defaultMethodWhiteList, | ||
| runtimeOptions.allowedProtoMethods | ||
| ), | ||
| defaultValue: runtimeOptions.allowProtoMethodsByDefault | ||
| } | ||
| }; | ||
| } | ||
|
|
||
| export function resultIsAllowed(result, protoAccessControl, propertyName) { | ||
| if (typeof result === 'function') { | ||
| return checkWhiteList(protoAccessControl.methods, propertyName); | ||
| } else { | ||
| return checkWhiteList(protoAccessControl.properties, propertyName); | ||
| } | ||
| } | ||
|
|
||
| function checkWhiteList(protoAccessControlForType, propertyName) { | ||
| if (protoAccessControlForType.whitelist[propertyName] !== undefined) { | ||
| return protoAccessControlForType.whitelist[propertyName] === true; | ||
| } | ||
| if (protoAccessControlForType.defaultValue !== undefined) { | ||
| return protoAccessControlForType.defaultValue; | ||
| } | ||
| logUnexpecedPropertyAccessOnce(propertyName); | ||
| return false; | ||
| } | ||
|
|
||
| function logUnexpecedPropertyAccessOnce(propertyName) { | ||
| if (loggedProperties[propertyName] !== true) { | ||
| loggedProperties[propertyName] = true; | ||
| logger.log( | ||
| 'error', | ||
| `Handlebars: Access has been denied to resolve the property "${propertyName}" because it is not an "own property" of its parent.\n` + | ||
| `You can add a runtime option to disable the check or this warning:\n` + | ||
| `See https://handlebarsjs.com/api-reference/runtime-options.html#options-to-control-prototype-access for details` | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| export function resetLoggedProperties() { | ||
| Object.keys(loggedProperties).forEach(propertyName => { | ||
| delete loggedProperties[propertyName]; | ||
| }); | ||
| } |