Allow Vega's emsfile to bypass sanitization (#17370)
* Allow Vega's emsfile to bypass sanitization Fixes https://github.com/elastic/kibana/issues/16669
This commit is contained in:
parent
49fae1d599
commit
1b4a7d1aaf
|
@ -1,6 +1,7 @@
|
|||
import _ from 'lodash';
|
||||
import expect from 'expect.js';
|
||||
import { VegaParser } from '../vega_parser';
|
||||
import { bypassExternalUrlCheck } from '../../vega_view/vega_base_view';
|
||||
|
||||
describe(`VegaParser._setDefaultValue`, () => {
|
||||
|
||||
|
@ -62,6 +63,7 @@ describe('VegaParser._resolveEsQueries', () => {
|
|||
getFileLayers: async () => [{ name: 'file1', url: 'url1' }]
|
||||
});
|
||||
await vp._resolveDataUrls();
|
||||
|
||||
expect(vp.spec).to.eql(expected);
|
||||
expect(vp.warnings).to.have.length(warnCount || 0);
|
||||
};
|
||||
|
@ -73,7 +75,9 @@ describe('VegaParser._resolveEsQueries', () => {
|
|||
it('es', test({ data: { url: { index: 'a' }, x: 1 } }, { data: { values: [42], x: 1 } }));
|
||||
it('es', test({ data: { url: { '%type%': 'elasticsearch', index: 'a' } } }, { data: { values: [42] } }));
|
||||
it('es arr', test({ arr: [{ data: { url: { index: 'a' }, x: 1 } }] }, { arr: [{ data: { values: [42], x: 1 } }] }));
|
||||
it('emsfile', test({ data: { url: { '%type%': 'emsfile', name: 'file1' } } }, { data: { url: 'url1' } }));
|
||||
it('emsfile', test(
|
||||
{ data: { url: { '%type%': 'emsfile', name: 'file1' } } },
|
||||
{ data: { url: bypassExternalUrlCheck('url1') } }));
|
||||
});
|
||||
|
||||
describe('VegaParser._parseSchema', () => {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { bypassExternalUrlCheck } from '../vega_view/vega_base_view';
|
||||
|
||||
/**
|
||||
* This class processes all Vega spec customizations,
|
||||
* converting url object parameters into query results.
|
||||
|
@ -38,7 +40,9 @@ export class EmsFileParser {
|
|||
if (!foundLayer) {
|
||||
throw new Error(`emsfile ${JSON.stringify(name)} does not exist`);
|
||||
}
|
||||
obj.url = foundLayer.url;
|
||||
|
||||
// This URL can bypass loader sanitization at the later stage
|
||||
obj.url = bypassExternalUrlCheck(foundLayer.url);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,13 @@ vega.scheme('elastic',
|
|||
['#00B3A4', '#3185FC', '#DB1374', '#490092', '#FEB6DB', '#F98510', '#E6C220', '#BFA180', '#920000', '#461A0A']
|
||||
);
|
||||
|
||||
const bypassToken = Symbol();
|
||||
|
||||
export function bypassExternalUrlCheck(url) {
|
||||
// processed in the loader.sanitize below
|
||||
return { url, bypassToken };
|
||||
}
|
||||
|
||||
export class VegaBaseView {
|
||||
constructor(vegaConfig, editorMode, parentEl, vegaParser, serviceSettings) {
|
||||
this._vegaConfig = vegaConfig;
|
||||
|
@ -58,20 +65,7 @@ export class VegaBaseView {
|
|||
}
|
||||
});
|
||||
|
||||
this._vegaViewConfig = {
|
||||
logLevel: vega.Warn,
|
||||
renderer: this._parser.renderer,
|
||||
};
|
||||
if (!this._vegaConfig.enableExternalUrls) {
|
||||
// Override URL loader and sanitizer to disable all URL-based requests
|
||||
const errorFunc = () => {
|
||||
throw new Error('External URLs are not enabled. Add "vega": {"enableExternalUrls": true} to kibana.yml');
|
||||
};
|
||||
const loader = vega.loader();
|
||||
loader.load = errorFunc;
|
||||
loader.sanitize = errorFunc;
|
||||
this._vegaViewConfig.loader = loader;
|
||||
}
|
||||
this._vegaViewConfig = this.createViewConfig();
|
||||
|
||||
// The derived class should create this method
|
||||
await this._initViewCustomizations();
|
||||
|
@ -80,6 +74,30 @@ export class VegaBaseView {
|
|||
}
|
||||
}
|
||||
|
||||
createViewConfig() {
|
||||
const config = {
|
||||
logLevel: vega.Warn,
|
||||
renderer: this._parser.renderer,
|
||||
};
|
||||
|
||||
// Override URL sanitizer to prevent external data loading (if disabled)
|
||||
const loader = vega.loader();
|
||||
const originalSanitize = loader.sanitize.bind(loader);
|
||||
loader.sanitize = (uri, options) => {
|
||||
if (uri.bypassToken === bypassToken) {
|
||||
// If uri has a bypass token, the uri was encoded by bypassExternalUrlCheck() above.
|
||||
// because user can only supply pure JSON data structure.
|
||||
uri = uri.url;
|
||||
} else if (!this._vegaConfig.enableExternalUrls) {
|
||||
throw new Error('External URLs are not enabled. Add vega.enableExternalUrls: true to kibana.yml');
|
||||
}
|
||||
return originalSanitize(uri, options);
|
||||
};
|
||||
config.loader = loader;
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
onError() {
|
||||
this._addMessage('err', Utils.formatErrorToStr(...arguments));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue