mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
* Backport #14994 * Update tests
This commit is contained in:
parent
3d9852edbf
commit
4df8a0bcde
5 changed files with 226 additions and 14 deletions
|
@ -22,9 +22,9 @@ describe('UrlFormat', function () {
|
|||
|
||||
describe('url template', function () {
|
||||
it('accepts a template', function () {
|
||||
const url = new UrlFormat({ urlTemplate: 'url: {{ value }}' });
|
||||
const url = new UrlFormat({ urlTemplate: 'http://{{ value }}' });
|
||||
expect(url.convert('url', 'html'))
|
||||
.to.be('<span ng-non-bindable><a href="url: url" target="_blank">url: url</a></span>');
|
||||
.to.be('<span ng-non-bindable><a href="http://url" target="_blank">http://url</a></span>');
|
||||
});
|
||||
|
||||
it('only outputs the url if the contentType === "text"', function () {
|
||||
|
@ -35,9 +35,9 @@ describe('UrlFormat', function () {
|
|||
|
||||
describe('label template', function () {
|
||||
it('accepts a template', function () {
|
||||
const url = new UrlFormat({ labelTemplate: 'extension: {{ value }}' });
|
||||
const url = new UrlFormat({ labelTemplate: 'extension: {{ value }}', urlTemplate: 'http://www.{{value}}.com' });
|
||||
expect(url.convert('php', 'html'))
|
||||
.to.be('<span ng-non-bindable><a href="php" target="_blank">extension: php</a></span>');
|
||||
.to.be('<span ng-non-bindable><a href="http://www.php.com" target="_blank">extension: php</a></span>');
|
||||
});
|
||||
|
||||
it('uses the label template for text formating', function () {
|
||||
|
@ -79,4 +79,89 @@ describe('UrlFormat', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('whitelist', function () {
|
||||
it('should assume a relative url if the value is not in the whitelist without a base path', function () {
|
||||
const url = new UrlFormat();
|
||||
const parsedUrl = {
|
||||
origin: 'http://kibana',
|
||||
basePath: '',
|
||||
};
|
||||
const converter = url.getConverterFor('html');
|
||||
|
||||
expect(converter('www.elastic.co', null, null, parsedUrl))
|
||||
.to.be('<span ng-non-bindable><a href="http://kibana/app/www.elastic.co" target="_blank">www.elastic.co</a></span>');
|
||||
|
||||
expect(converter('elastic.co', null, null, parsedUrl))
|
||||
.to.be('<span ng-non-bindable><a href="http://kibana/app/elastic.co" target="_blank">elastic.co</a></span>');
|
||||
|
||||
expect(converter('elastic', null, null, parsedUrl))
|
||||
.to.be('<span ng-non-bindable><a href="http://kibana/app/elastic" target="_blank">elastic</a></span>');
|
||||
|
||||
expect(converter('ftp://elastic.co', null, null, parsedUrl))
|
||||
.to.be('<span ng-non-bindable><a href="http://kibana/app/ftp://elastic.co" target="_blank">ftp://elastic.co</a></span>');
|
||||
});
|
||||
|
||||
it('should assume a relative url if the value is not in the whitelist with a basepath', function () {
|
||||
const url = new UrlFormat();
|
||||
const parsedUrl = {
|
||||
origin: 'http://kibana',
|
||||
basePath: '/xyz',
|
||||
};
|
||||
const converter = url.getConverterFor('html');
|
||||
|
||||
expect(converter('www.elastic.co', null, null, parsedUrl))
|
||||
.to.be('<span ng-non-bindable><a href="http://kibana/xyz/app/www.elastic.co" target="_blank">www.elastic.co</a></span>');
|
||||
|
||||
expect(converter('elastic.co', null, null, parsedUrl))
|
||||
.to.be('<span ng-non-bindable><a href="http://kibana/xyz/app/elastic.co" target="_blank">elastic.co</a></span>');
|
||||
|
||||
expect(converter('elastic', null, null, parsedUrl))
|
||||
.to.be('<span ng-non-bindable><a href="http://kibana/xyz/app/elastic" target="_blank">elastic</a></span>');
|
||||
|
||||
expect(converter('ftp://elastic.co', null, null, parsedUrl))
|
||||
.to.be('<span ng-non-bindable><a href="http://kibana/xyz/app/ftp://elastic.co" target="_blank">ftp://elastic.co</a></span>');
|
||||
});
|
||||
|
||||
it('should rely on parsedUrl', function () {
|
||||
const url = new UrlFormat();
|
||||
const parsedUrl = {
|
||||
origin: 'http://kibana.host.com',
|
||||
basePath: '/abc',
|
||||
};
|
||||
const converter = url.getConverterFor('html');
|
||||
|
||||
expect(converter('../app/kibana', null, null, parsedUrl))
|
||||
.to.be('<span ng-non-bindable><a href="http://kibana.host.com/abc/app/../app/kibana" target="_blank">../app/kibana</a></span>');
|
||||
});
|
||||
|
||||
it('should fail gracefully if there are no parsedUrl provided', function () {
|
||||
const url = new UrlFormat();
|
||||
|
||||
expect(url.convert('../app/kibana', 'html'))
|
||||
.to.be('<span ng-non-bindable>../app/kibana</span>');
|
||||
|
||||
expect(url.convert('http://www.elastic.co', 'html'))
|
||||
.to.be('<span ng-non-bindable><a href="http://www.elastic.co" target="_blank">http://www.elastic.co</a></span>');
|
||||
});
|
||||
|
||||
it('should support multiple types of relative urls', function () {
|
||||
const url = new UrlFormat();
|
||||
const parsedUrl = {
|
||||
origin: 'http://kibana.host.com',
|
||||
pathname: '/nbc/app/kibana#/discover',
|
||||
basePath: '/nbc',
|
||||
};
|
||||
const converter = url.getConverterFor('html');
|
||||
|
||||
expect(converter('#/foo', null, null, parsedUrl))
|
||||
.to.be('<span ng-non-bindable><a href="http://kibana.host.com/nbc/app/kibana#/discover#/foo" target="_blank">#/foo</a></span>');
|
||||
|
||||
expect(converter('/nbc/app/kibana#/discover', null, null, parsedUrl))
|
||||
.to.be('<span ng-non-bindable><a href="http://kibana.host.com/nbc/app/kibana#/discover" target="_blank">/nbc/app/kibana#/discover</a></span>');
|
||||
|
||||
expect(converter('../foo/bar', null, null, parsedUrl))
|
||||
.to.be('<span ng-non-bindable><a href="http://kibana.host.com/nbc/app/../foo/bar" target="_blank">../foo/bar</a></span>');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -2,6 +2,7 @@ import _ from 'lodash';
|
|||
import { getHighlightHtml } from '../../highlight/highlight_html';
|
||||
|
||||
const templateMatchRE = /{{([\s\S]+?)}}/g;
|
||||
const whitelistUrlSchemes = ['http://', 'https://'];
|
||||
|
||||
export function createUrlFormat(FieldFormat) {
|
||||
class UrlFormat extends FieldFormat {
|
||||
|
@ -83,7 +84,7 @@ export function createUrlFormat(FieldFormat) {
|
|||
return this._formatLabel(value);
|
||||
},
|
||||
|
||||
html: function (rawValue, field, hit) {
|
||||
html: function (rawValue, field, hit, parsedUrl) {
|
||||
const url = _.escape(this._formatUrl(rawValue));
|
||||
const label = _.escape(this._formatLabel(rawValue, url));
|
||||
|
||||
|
@ -98,6 +99,38 @@ export function createUrlFormat(FieldFormat) {
|
|||
|
||||
return `<img src="${url}" alt="${imageLabel}">`;
|
||||
default:
|
||||
const inWhitelist = whitelistUrlSchemes.some(scheme => url.indexOf(scheme) === 0);
|
||||
if (!inWhitelist && !parsedUrl) {
|
||||
return url;
|
||||
}
|
||||
|
||||
let prefix = '';
|
||||
/**
|
||||
* This code attempts to convert a relative url into a kibana absolute url
|
||||
*
|
||||
* SUPPORTED:
|
||||
* - /app/kibana/
|
||||
* - ../app/kibana
|
||||
* - #/discover
|
||||
*
|
||||
* UNSUPPORTED
|
||||
* - app/kibana
|
||||
*/
|
||||
if (!inWhitelist) {
|
||||
// Handles urls like: `#/discover`
|
||||
if (url[0] === '#') {
|
||||
prefix = `${parsedUrl.origin}${parsedUrl.pathname}`;
|
||||
}
|
||||
// Handle urls like: `/app/kibana` or `/xyz/app/kibana`
|
||||
else if (url.indexOf(parsedUrl.basePath || '/') === 0) {
|
||||
prefix = `${parsedUrl.origin}`;
|
||||
}
|
||||
// Handle urls like: `../app/kibana`
|
||||
else {
|
||||
prefix = `${parsedUrl.origin}${parsedUrl.basePath}/app/`;
|
||||
}
|
||||
}
|
||||
|
||||
let linkLabel;
|
||||
|
||||
if (hit && hit.highlight && hit.highlight[field.name]) {
|
||||
|
@ -106,7 +139,7 @@ export function createUrlFormat(FieldFormat) {
|
|||
linkLabel = label;
|
||||
}
|
||||
|
||||
return `<a href="${url}" target="_blank">${linkLabel}</a>`;
|
||||
return `<a href="${prefix}${url}" target="_blank">${linkLabel}</a>`;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -44,11 +44,11 @@ describe('Url Format', function () {
|
|||
|
||||
describe('url template', function () {
|
||||
it('accepts a template', function () {
|
||||
const url = new Url({ urlTemplate: 'url: {{ value }}' });
|
||||
const url = new Url({ urlTemplate: 'http://{{ value }}' });
|
||||
const $a = unwrap($(url.convert('url', 'html')));
|
||||
expect($a.is('a')).to.be(true);
|
||||
expect($a.size()).to.be(1);
|
||||
expect($a.attr('href')).to.be('url: url');
|
||||
expect($a.attr('href')).to.be('http://url');
|
||||
expect($a.attr('target')).to.be('_blank');
|
||||
expect($a.children().size()).to.be(0);
|
||||
});
|
||||
|
@ -61,11 +61,11 @@ describe('Url Format', function () {
|
|||
|
||||
describe('label template', function () {
|
||||
it('accepts a template', function () {
|
||||
const url = new Url({ labelTemplate: 'extension: {{ value }}' });
|
||||
const url = new Url({ labelTemplate: 'extension: {{ value }}', urlTemplate: 'http://www.{{value}}.com' });
|
||||
const $a = unwrap($(url.convert('php', 'html')));
|
||||
expect($a.is('a')).to.be(true);
|
||||
expect($a.size()).to.be(1);
|
||||
expect($a.attr('href')).to.be('php');
|
||||
expect($a.attr('href')).to.be('http://www.php.com');
|
||||
expect($a.html()).to.be('extension: php');
|
||||
});
|
||||
|
||||
|
@ -109,5 +109,92 @@ describe('Url Format', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('whitelist', function () {
|
||||
it('should assume a relative url if the value is not in the whitelist without a base path', function () {
|
||||
const url = new Url();
|
||||
const parsedUrl = {
|
||||
origin: 'http://kibana',
|
||||
basePath: '',
|
||||
};
|
||||
const converter = url.getConverterFor('html');
|
||||
|
||||
expect(converter('www.elastic.co', null, null, parsedUrl))
|
||||
.to.be('<span ng-non-bindable><a href="http://kibana/app/www.elastic.co" target="_blank">www.elastic.co</a></span>');
|
||||
|
||||
expect(converter('elastic.co', null, null, parsedUrl))
|
||||
.to.be('<span ng-non-bindable><a href="http://kibana/app/elastic.co" target="_blank">elastic.co</a></span>');
|
||||
|
||||
expect(converter('elastic', null, null, parsedUrl))
|
||||
.to.be('<span ng-non-bindable><a href="http://kibana/app/elastic" target="_blank">elastic</a></span>');
|
||||
|
||||
expect(converter('ftp://elastic.co', null, null, parsedUrl))
|
||||
.to.be('<span ng-non-bindable><a href="http://kibana/app/ftp://elastic.co" target="_blank">ftp://elastic.co</a></span>');
|
||||
});
|
||||
|
||||
it('should assume a relative url if the value is not in the whitelist with a basepath', function () {
|
||||
const url = new Url();
|
||||
const parsedUrl = {
|
||||
origin: 'http://kibana',
|
||||
basePath: '/xyz',
|
||||
};
|
||||
const converter = url.getConverterFor('html');
|
||||
|
||||
expect(converter('www.elastic.co', null, null, parsedUrl))
|
||||
.to.be('<span ng-non-bindable><a href="http://kibana/xyz/app/www.elastic.co" target="_blank">www.elastic.co</a></span>');
|
||||
|
||||
expect(converter('elastic.co', null, null, parsedUrl))
|
||||
.to.be('<span ng-non-bindable><a href="http://kibana/xyz/app/elastic.co" target="_blank">elastic.co</a></span>');
|
||||
|
||||
expect(converter('elastic', null, null, parsedUrl))
|
||||
.to.be('<span ng-non-bindable><a href="http://kibana/xyz/app/elastic" target="_blank">elastic</a></span>');
|
||||
|
||||
expect(converter('ftp://elastic.co', null, null, parsedUrl))
|
||||
.to.be('<span ng-non-bindable><a href="http://kibana/xyz/app/ftp://elastic.co" target="_blank">ftp://elastic.co</a></span>');
|
||||
});
|
||||
|
||||
it('should rely on parsedUrl', function () {
|
||||
const url = new Url();
|
||||
const parsedUrl = {
|
||||
origin: 'http://kibana.host.com',
|
||||
basePath: '/abc',
|
||||
};
|
||||
const converter = url.getConverterFor('html');
|
||||
|
||||
expect(converter('../app/kibana', null, null, parsedUrl))
|
||||
.to.be('<span ng-non-bindable><a href="http://kibana.host.com/abc/app/../app/kibana" target="_blank">../app/kibana</a></span>');
|
||||
});
|
||||
|
||||
it('should fail gracefully if there are no parsedUrl provided', function () {
|
||||
const url = new Url();
|
||||
const parsedUrl = null;
|
||||
const converter = url.getConverterFor('html');
|
||||
|
||||
expect(converter('../app/kibana', null, null, parsedUrl))
|
||||
.to.be('<span ng-non-bindable>../app/kibana</span>');
|
||||
|
||||
expect(converter('http://www.elastic.co', null, null, parsedUrl))
|
||||
.to.be('<span ng-non-bindable><a href="http://www.elastic.co" target="_blank">http://www.elastic.co</a></span>');
|
||||
});
|
||||
|
||||
it('should support multiple types of relative urls', function () {
|
||||
const url = new Url();
|
||||
const parsedUrl = {
|
||||
origin: 'http://kibana.host.com',
|
||||
pathname: '/nbc/app/kibana#/discover',
|
||||
basePath: '/nbc',
|
||||
};
|
||||
const converter = url.getConverterFor('html');
|
||||
|
||||
expect(converter('#/foo', null, null, parsedUrl))
|
||||
.to.be('<span ng-non-bindable><a href="http://kibana.host.com/nbc/app/kibana#/discover#/foo" target="_blank">#/foo</a></span>');
|
||||
|
||||
expect(converter('/nbc/app/kibana#/discover', null, null, parsedUrl))
|
||||
.to.be('<span ng-non-bindable><a href="http://kibana.host.com/nbc/app/kibana#/discover" target="_blank">/nbc/app/kibana#/discover</a></span>');
|
||||
|
||||
expect(converter('../foo/bar', null, null, parsedUrl))
|
||||
.to.be('<span ng-non-bindable><a href="http://kibana.host.com/nbc/app/../foo/bar" target="_blank">../foo/bar</a></span>');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,17 +4,17 @@ import { getHighlightHtml } from '../../core_plugins/kibana/common/highlight/hig
|
|||
|
||||
const types = {
|
||||
html: function (format, convert) {
|
||||
function recurse(value, field, hit) {
|
||||
function recurse(value, field, hit, meta) {
|
||||
if (value == null) {
|
||||
return asPrettyString(value);
|
||||
}
|
||||
|
||||
if (!value || typeof value.map !== 'function') {
|
||||
return convert.call(format, value, field, hit);
|
||||
return convert.call(format, value, field, hit, meta);
|
||||
}
|
||||
|
||||
const subVals = value.map(v => {
|
||||
return recurse(v, field, hit);
|
||||
return recurse(v, field, hit, meta);
|
||||
});
|
||||
const useMultiLine = subVals.some(sub => {
|
||||
return sub.indexOf('\n') > -1;
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import _ from 'lodash';
|
||||
import chrome from 'ui/chrome';
|
||||
|
||||
// Takes a hit, merges it with any stored/scripted fields, and with the metaFields
|
||||
// returns a formatted version
|
||||
|
||||
|
@ -7,7 +9,12 @@ export function formatHit(indexPattern, defaultFormat) {
|
|||
function convert(hit, val, fieldName) {
|
||||
const field = indexPattern.fields.byName[fieldName];
|
||||
if (!field) return defaultFormat.convert(val, 'html');
|
||||
return field.format.getConverterFor('html')(val, field, hit);
|
||||
const parsedUrl = {
|
||||
origin: window.location.origin,
|
||||
pathname: window.location.pathname,
|
||||
basePath: chrome.getBasePath(),
|
||||
};
|
||||
return field.format.getConverterFor('html')(val, field, hit, parsedUrl);
|
||||
}
|
||||
|
||||
function formatHit(hit) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue