Skip to content

Commit

Permalink
backport fixes from 4.x
Browse files Browse the repository at this point in the history
  • Loading branch information
nknapp committed Feb 23, 2020
1 parent 8ba9159 commit 156061e
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 8 deletions.
2 changes: 1 addition & 1 deletion lib/handlebars/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ function registerDefaultHelpers(instance) {
if (!obj) {
return obj;
}
if (field === 'constructor' && !obj.propertyIsEnumerable(field)) {
if (Utils.dangerousPropertyRegex.test(String(field)) && !Object.prototype.hasOwnProperty.call(obj, field)) {
return undefined;
}
return obj[field];
Expand Down
19 changes: 12 additions & 7 deletions lib/handlebars/compiler/javascript-compiler.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { COMPILER_REVISION, REVISION_CHANGES } from '../base';
import Exception from '../exception';
import {isArray} from '../utils';
import {isArray, dangerousPropertyRegex} from '../utils';
import CodeGen from './code-gen';

function Literal(value) {
Expand All @@ -13,13 +13,18 @@ JavaScriptCompiler.prototype = {
// PUBLIC API: You can override these methods in a subclass to provide
// alternative compiled forms for name lookup and buffering semantics
nameLookup: function(parent, name /* , type*/) {
if (name === 'constructor') {
return ['(', parent, '.propertyIsEnumerable(\'constructor\') ? ', parent, '.constructor : undefined', ')'];
if (dangerousPropertyRegex.test(name)) {
const isOwnProperty = [ this.aliasable('Object.prototype.hasOwnProperty'), '.call(', parent, ',', JSON.stringify(name), ')'];
return ['(', isOwnProperty, '?', _actualLookup(), ' : undefined)'];
}
if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) {
return [parent, '.', name];
} else {
return [parent, "['", name, "']"];
return _actualLookup();

function _actualLookup() {
if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) {
return [parent, '.', name];
} else {
return [parent, '[', JSON.stringify(name), ']'];
}
}
},
depthedLookup: function(name) {
Expand Down
2 changes: 2 additions & 0 deletions lib/handlebars/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,5 @@ export function blockParams(params, ids) {
export function appendContextPath(contextPath, id) {
return (contextPath ? contextPath + '.' : '') + id;
}

export const dangerousPropertyRegex = /^(constructor|__defineGetter__|__defineSetter__|__lookupGetter__|__proto__)$/;
16 changes: 16 additions & 0 deletions spec/security.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,20 @@ describe('security issues', function() {
new TestClass(), 'xyz');
});
});

describe('GH-1595', function() {
it('properties, that are required to be enumerable', function() {
shouldCompileTo('{{constructor.name}}', {}, '');
shouldCompileTo('{{__defineGetter__.name}}', {}, '');
shouldCompileTo('{{__defineSetter__.name}}', {}, '');
shouldCompileTo('{{__lookupGetter__.name}}', {}, '');
shouldCompileTo('{{__proto__.__defineGetter__.name}}', {}, '');

shouldCompileTo('{{lookup this "constructor"}}', {}, '');
shouldCompileTo('{{lookup this "__defineGetter__"}}', {}, '');
shouldCompileTo('{{lookup this "__defineSetter__"}}', {}, '');
shouldCompileTo('{{lookup this "__lookupGetter__"}}', {}, '');
shouldCompileTo('{{lookup this "__proto__"}}', {}, '');
});
});
});

0 comments on commit 156061e

Please sign in to comment.