Skip to content

Commit 0b4b423

Browse files
authored
Fall back to default renderer when render is not a function (#562)
1 parent b77aa99 commit 0b4b423

5 files changed

Lines changed: 34 additions & 6 deletions

File tree

‎.gitignore‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
env.test.sh
22
dist
3-
node_modules
3+
node_modules
4+
.idea

‎API.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ Set the render function used in the results dropdown
214214

215215
#### Parameters
216216

217-
* `fn` **[Function][85]** The function to use as a render function. This function accepts a single [extended GeoJSON][86] object as input and returns a string.
217+
* `fn` **[Function][85]** The function to use as a render function. This function accepts a single [extended GeoJSON][86] object as input and returns a string. If `fn` is not a function, the default render function is used.
218218

219219
Returns **[MapboxGeocoder][2]** this
220220

‎CHANGELOG.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
## HEAD
22

3+
### Bug fixes 🐛
4+
5+
- Fix potential XSS when the `render` option is not a function.
6+
37
## 5.1.2
48

59
### Bug fixes 🐛

‎lib/index.js‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,13 +1121,12 @@ MapboxGeocoder.prototype = {
11211121

11221122
/**
11231123
* Set the render function used in the results dropdown
1124-
* @param {Function} fn The function to use as a render function. This function accepts a single [extended GeoJSON](https://docs.mapbox.com/api/search/geocoding-v5/#geocoding-response-object) object as input and returns a string.
1124+
* @param {Function} fn The function to use as a render function. This function accepts a single [extended GeoJSON](https://docs.mapbox.com/api/search/geocoding-v5/#geocoding-response-object) object as input and returns a string. If `fn` is not a function, the default render function is used.
11251125
* @returns {MapboxGeocoder} this
11261126
*/
11271127
setRenderFunction: function(fn){
1128-
if (fn && typeof(fn) == "function"){
1129-
this._typeahead.render = fn;
1130-
}
1128+
// Fall back to the escaping default: keeping the suggestions library's own renderer would inject place_name unescaped
1129+
this._typeahead.render = typeof fn === 'function' ? fn : MapboxGeocoder.prototype.options.render;
11311130
return this;
11321131
},
11331132

‎test/test.geocoder.js‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,30 @@ test('geocoder', function(tt) {
706706
t.equals(geocoder._typeahead.render(fixture), 'feature id is abc123', 'render function is applied properly on the typeahead');
707707
})
708708

709+
tt.test('default render function escapes place_name', function(t){
710+
t.plan(2);
711+
var html = MapboxGeocoder.prototype.options.render({ place_name: '<img src=x>Cafe, Berlin' });
712+
t.ok(html.indexOf('&lt;img src=x&gt;Cafe') > -1, 'place_name is escaped');
713+
t.equals(html.indexOf('<img'), -1, 'no raw HTML from place_name');
714+
});
715+
716+
// Compare by identity: calling the suggestions library's renderer directly loops forever on its initial empty query
717+
tt.test('options.render that is not a function falls back to the default', function(t){
718+
var values = [undefined, null, false, 'not a function'];
719+
t.plan(values.length);
720+
values.forEach(function(value){
721+
setup({ render: value });
722+
t.equals(geocoder.getRenderFunction(), MapboxGeocoder.prototype.options.render, 'default render function is used when render is ' + String(value));
723+
});
724+
});
725+
726+
tt.test('setRenderFunction with non-function input restores the default', function(t){
727+
t.plan(1);
728+
setup({ render: function(item){ return item.place_name; } });
729+
geocoder.setRenderFunction(null);
730+
t.equals(geocoder.getRenderFunction(), MapboxGeocoder.prototype.options.render, 'default render function is used');
731+
});
732+
709733
tt.test('setRenderFunction with no input', function(t){
710734
t.plan(2);
711735
setup({});

0 commit comments

Comments
 (0)